@@ -2162,92 +2162,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
21622162
21632163 self . ascribe_types ( block, ascriptions) ;
21642164
2165- // rust-lang/rust#27282: The `autoref` business deserves some
2166- // explanation here.
2167- //
2168- // The intent of the `autoref` flag is that when it is true,
2169- // then any pattern bindings of type T will map to a `&T`
2170- // within the context of the guard expression, but will
2171- // continue to map to a `T` in the context of the arm body. To
2172- // avoid surfacing this distinction in the user source code
2173- // (which would be a severe change to the language and require
2174- // far more revision to the compiler), when `autoref` is true,
2175- // then any occurrence of the identifier in the guard
2176- // expression will automatically get a deref op applied to it.
2177- //
2178- // So an input like:
2179- //
2180- // ```
2181- // let place = Foo::new();
2182- // match place { foo if inspect(foo)
2183- // => feed(foo), ... }
2184- // ```
2185- //
2186- // will be treated as if it were really something like:
2187- //
2188- // ```
2189- // let place = Foo::new();
2190- // match place { Foo { .. } if { let tmp1 = &place; inspect(*tmp1) }
2191- // => { let tmp2 = place; feed(tmp2) }, ... }
2192- // ```
2193- //
2194- // And an input like:
2195- //
2196- // ```
2197- // let place = Foo::new();
2198- // match place { ref mut foo if inspect(foo)
2199- // => feed(foo), ... }
2200- // ```
2201- //
2202- // will be treated as if it were really something like:
2203- //
2204- // ```
2205- // let place = Foo::new();
2206- // match place { Foo { .. } if { let tmp1 = & &mut place; inspect(*tmp1) }
2207- // => { let tmp2 = &mut place; feed(tmp2) }, ... }
2208- // ```
2209- //
2210- // In short, any pattern binding will always look like *some*
2211- // kind of `&T` within the guard at least in terms of how the
2212- // MIR-borrowck views it, and this will ensure that guard
2213- // expressions cannot mutate their the match inputs via such
2214- // bindings. (It also ensures that guard expressions can at
2215- // most *copy* values from such bindings; non-Copy things
2216- // cannot be moved via pattern bindings in guard expressions.)
2217- //
2218- // ----
2219- //
2220- // Implementation notes (under assumption `autoref` is true).
2221- //
2222- // To encode the distinction above, we must inject the
2223- // temporaries `tmp1` and `tmp2`.
2224- //
2225- // There are two cases of interest: binding by-value, and binding by-ref.
2226- //
2227- // 1. Binding by-value: Things are simple.
2228- //
2229- // * Establishing `tmp1` creates a reference into the
2230- // matched place. This code is emitted by
2231- // bind_matched_candidate_for_guard.
2232- //
2233- // * `tmp2` is only initialized "lazily", after we have
2234- // checked the guard. Thus, the code that can trigger
2235- // moves out of the candidate can only fire after the
2236- // guard evaluated to true. This initialization code is
2237- // emitted by bind_matched_candidate_for_arm.
2238- //
2239- // 2. Binding by-reference: Things are tricky.
2240- //
2241- // * Here, the guard expression wants a `&&` or `&&mut`
2242- // into the original input. This means we need to borrow
2243- // the reference that we create for the arm.
2244- // * So we eagerly create the reference for the arm and then take a
2245- // reference to that.
2165+ // Lower an instance of the arm guard (if present) for this candidate,
2166+ // and then perform bindings for the arm body.
22462167 if let Some ( ( arm, match_scope) ) = arm_match_scope
22472168 && let Some ( guard) = arm. guard
22482169 {
22492170 let tcx = self . tcx ;
22502171
2172+ // Bindings for guards require some extra handling to automatically
2173+ // insert implicit references/dereferences.
22512174 self . bind_matched_candidate_for_guard ( block, schedule_drops, bindings. clone ( ) ) ;
22522175 let guard_frame = GuardFrame {
22532176 locals : bindings. clone ( ) . map ( |b| GuardFrameLocal :: new ( b. var_id ) ) . collect ( ) ,
@@ -2387,6 +2310,82 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
23872310 }
23882311 }
23892312
2313+ /// Binding for guards is a bit different from binding for the arm body,
2314+ /// because an extra layer of implicit reference/dereference is added.
2315+ ///
2316+ /// The idea is that any pattern bindings of type T will map to a `&T` within
2317+ /// the context of the guard expression, but will continue to map to a `T`
2318+ /// in the context of the arm body. To avoid surfacing this distinction in
2319+ /// the user source code (which would be a severe change to the language and
2320+ /// require far more revision to the compiler), any occurrence of the
2321+ /// identifier in the guard expression will automatically get a deref op
2322+ /// applied to it. (See the caller of [`Self::is_bound_var_in_guard`].)
2323+ ///
2324+ /// So an input like:
2325+ ///
2326+ /// ```ignore (illustrative)
2327+ /// let place = Foo::new();
2328+ /// match place { foo if inspect(foo)
2329+ /// => feed(foo), ... }
2330+ /// ```
2331+ ///
2332+ /// will be treated as if it were really something like:
2333+ ///
2334+ /// ```ignore (illustrative)
2335+ /// let place = Foo::new();
2336+ /// match place { Foo { .. } if { let tmp1 = &place; inspect(*tmp1) }
2337+ /// => { let tmp2 = place; feed(tmp2) }, ... }
2338+ /// ```
2339+ ///
2340+ /// And an input like:
2341+ ///
2342+ /// ```ignore (illustrative)
2343+ /// let place = Foo::new();
2344+ /// match place { ref mut foo if inspect(foo)
2345+ /// => feed(foo), ... }
2346+ /// ```
2347+ ///
2348+ /// will be treated as if it were really something like:
2349+ ///
2350+ /// ```ignore (illustrative)
2351+ /// let place = Foo::new();
2352+ /// match place { Foo { .. } if { let tmp1 = & &mut place; inspect(*tmp1) }
2353+ /// => { let tmp2 = &mut place; feed(tmp2) }, ... }
2354+ /// ```
2355+ /// ---
2356+ ///
2357+ /// ## Implementation notes
2358+ ///
2359+ /// To encode the distinction above, we must inject the
2360+ /// temporaries `tmp1` and `tmp2`.
2361+ ///
2362+ /// There are two cases of interest: binding by-value, and binding by-ref.
2363+ ///
2364+ /// 1. Binding by-value: Things are simple.
2365+ ///
2366+ /// * Establishing `tmp1` creates a reference into the
2367+ /// matched place. This code is emitted by
2368+ /// [`Self::bind_matched_candidate_for_guard`].
2369+ ///
2370+ /// * `tmp2` is only initialized "lazily", after we have
2371+ /// checked the guard. Thus, the code that can trigger
2372+ /// moves out of the candidate can only fire after the
2373+ /// guard evaluated to true. This initialization code is
2374+ /// emitted by [`Self::bind_matched_candidate_for_arm_body`].
2375+ ///
2376+ /// 2. Binding by-reference: Things are tricky.
2377+ ///
2378+ /// * Here, the guard expression wants a `&&` or `&&mut`
2379+ /// into the original input. This means we need to borrow
2380+ /// the reference that we create for the arm.
2381+ /// * So we eagerly create the reference for the arm and then take a
2382+ /// reference to that.
2383+ ///
2384+ /// ---
2385+ ///
2386+ /// See these PRs for some historical context:
2387+ /// - <https://github.com/rust-lang/rust/pull/49870> (introduction of autoref)
2388+ /// - <https://github.com/rust-lang/rust/pull/59114> (always use autoref)
23902389 fn bind_matched_candidate_for_guard < ' b > (
23912390 & mut self ,
23922391 block : BasicBlock ,
@@ -2418,10 +2417,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
24182417 ) ;
24192418 match binding. binding_mode . 0 {
24202419 ByRef :: No => {
2420+ // The arm binding will be by value, so for the guard binding
2421+ // just take a shared reference to the matched place.
24212422 let rvalue = Rvalue :: Ref ( re_erased, BorrowKind :: Shared , binding. source ) ;
24222423 self . cfg . push_assign ( block, source_info, ref_for_guard, rvalue) ;
24232424 }
24242425 ByRef :: Yes ( mutbl) => {
2426+ // The arm binding will be by reference, so eagerly create it now.
24252427 let value_for_arm = self . storage_live_binding (
24262428 block,
24272429 binding. var_id ,
@@ -2433,6 +2435,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
24332435 let rvalue =
24342436 Rvalue :: Ref ( re_erased, util:: ref_pat_borrow_kind ( mutbl) , binding. source ) ;
24352437 self . cfg . push_assign ( block, source_info, value_for_arm, rvalue) ;
2438+ // For the guard binding, take a shared reference to that reference.
24362439 let rvalue = Rvalue :: Ref ( re_erased, BorrowKind :: Shared , value_for_arm) ;
24372440 self . cfg . push_assign ( block, source_info, ref_for_guard, rvalue) ;
24382441 }
0 commit comments