@@ -2177,87 +2177,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
21772177
21782178 self . ascribe_types ( block, ascriptions) ;
21792179
2180- // rust-lang/rust#27282: The `autoref` business deserves some
2181- // explanation here.
2182- //
2183- // The intent of the `autoref` flag is that when it is true,
2184- // then any pattern bindings of type T will map to a `&T`
2185- // within the context of the guard expression, but will
2186- // continue to map to a `T` in the context of the arm body. To
2187- // avoid surfacing this distinction in the user source code
2188- // (which would be a severe change to the language and require
2189- // far more revision to the compiler), when `autoref` is true,
2190- // then any occurrence of the identifier in the guard
2191- // expression will automatically get a deref op applied to it.
2192- //
2193- // So an input like:
2194- //
2195- // ```
2196- // let place = Foo::new();
2197- // match place { foo if inspect(foo)
2198- // => feed(foo), ... }
2199- // ```
2200- //
2201- // will be treated as if it were really something like:
2202- //
2203- // ```
2204- // let place = Foo::new();
2205- // match place { Foo { .. } if { let tmp1 = &place; inspect(*tmp1) }
2206- // => { let tmp2 = place; feed(tmp2) }, ... }
2207- // ```
2208- //
2209- // And an input like:
2210- //
2211- // ```
2212- // let place = Foo::new();
2213- // match place { ref mut foo if inspect(foo)
2214- // => feed(foo), ... }
2215- // ```
2216- //
2217- // will be treated as if it were really something like:
2218- //
2219- // ```
2220- // let place = Foo::new();
2221- // match place { Foo { .. } if { let tmp1 = & &mut place; inspect(*tmp1) }
2222- // => { let tmp2 = &mut place; feed(tmp2) }, ... }
2223- // ```
2224- //
2225- // In short, any pattern binding will always look like *some*
2226- // kind of `&T` within the guard at least in terms of how the
2227- // MIR-borrowck views it, and this will ensure that guard
2228- // expressions cannot mutate their the match inputs via such
2229- // bindings. (It also ensures that guard expressions can at
2230- // most *copy* values from such bindings; non-Copy things
2231- // cannot be moved via pattern bindings in guard expressions.)
2232- //
2233- // ----
2234- //
2235- // Implementation notes (under assumption `autoref` is true).
2236- //
2237- // To encode the distinction above, we must inject the
2238- // temporaries `tmp1` and `tmp2`.
2239- //
2240- // There are two cases of interest: binding by-value, and binding by-ref.
2241- //
2242- // 1. Binding by-value: Things are simple.
2243- //
2244- // * Establishing `tmp1` creates a reference into the
2245- // matched place. This code is emitted by
2246- // bind_matched_candidate_for_guard.
2247- //
2248- // * `tmp2` is only initialized "lazily", after we have
2249- // checked the guard. Thus, the code that can trigger
2250- // moves out of the candidate can only fire after the
2251- // guard evaluated to true. This initialization code is
2252- // emitted by bind_matched_candidate_for_arm.
2253- //
2254- // 2. Binding by-reference: Things are tricky.
2255- //
2256- // * Here, the guard expression wants a `&&` or `&&mut`
2257- // into the original input. This means we need to borrow
2258- // the reference that we create for the arm.
2259- // * So we eagerly create the reference for the arm and then take a
2260- // reference to that.
2180+ // Lower an instance of the arm guard (if present) for this candidate,
2181+ // and then perform bindings for the arm body.
22612182 if let Some ( ( arm, match_scope) ) = arm_match_scope
22622183 && let Some ( guard) = arm. guard
22632184 {
@@ -2402,6 +2323,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
24022323 }
24032324 }
24042325
2326+ /// Binding for guards is a bit different from binding for the arm body,
2327+ /// because an extra layer of implicit reference/dereference is added.
2328+ ///
2329+ /// The idea is that any pattern bindings of type T will map to a `&T` within
2330+ /// the context of the guard expression, but will continue to map to a `T`
2331+ /// in the context of the arm body. To avoid surfacing this distinction in
2332+ /// the user source code (which would be a severe change to the language and
2333+ /// require far more revision to the compiler), any occurrence of the
2334+ /// identifier in the guard expression will automatically get a deref op
2335+ /// applied to it. (See the caller of [`Self::is_bound_var_in_guard`].)
2336+ ///
2337+ /// See these PRs for some historical context:
2338+ /// - https://github.com/rust-lang/rust/pull/49870 (introduction of autoref)
2339+ /// - https://github.com/rust-lang/rust/pull/59114 (always use autoref)
24052340 fn bind_matched_candidate_for_guard < ' b > (
24062341 & mut self ,
24072342 block : BasicBlock ,
@@ -2433,10 +2368,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
24332368 ) ;
24342369 match binding. binding_mode . 0 {
24352370 ByRef :: No => {
2371+ // The arm binding will be by value, so for the guard binding
2372+ // just take a shared reference to the matched place.
24362373 let rvalue = Rvalue :: Ref ( re_erased, BorrowKind :: Shared , binding. source ) ;
24372374 self . cfg . push_assign ( block, source_info, ref_for_guard, rvalue) ;
24382375 }
24392376 ByRef :: Yes ( mutbl) => {
2377+ // The arm binding will be by reference, so eagerly create it now.
24402378 let value_for_arm = self . storage_live_binding (
24412379 block,
24422380 binding. var_id ,
@@ -2448,6 +2386,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
24482386 let rvalue =
24492387 Rvalue :: Ref ( re_erased, util:: ref_pat_borrow_kind ( mutbl) , binding. source ) ;
24502388 self . cfg . push_assign ( block, source_info, value_for_arm, rvalue) ;
2389+ // For the guard binding, take a shared reference to that reference.
24512390 let rvalue = Rvalue :: Ref ( re_erased, BorrowKind :: Shared , value_for_arm) ;
24522391 self . cfg . push_assign ( block, source_info, ref_for_guard, rvalue) ;
24532392 }
0 commit comments