@@ -2177,92 +2177,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
2177
2177
2178
2178
self . ascribe_types ( block, ascriptions) ;
2179
2179
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.
2261
2182
if let Some ( ( arm, match_scope) ) = arm_match_scope
2262
2183
&& let Some ( guard) = arm. guard
2263
2184
{
2264
2185
let tcx = self . tcx ;
2265
2186
2187
+ // Bindings for guards require some extra handling to automatically
2188
+ // insert implicit references/dereferences.
2266
2189
self . bind_matched_candidate_for_guard ( block, schedule_drops, bindings. clone ( ) ) ;
2267
2190
let guard_frame = GuardFrame {
2268
2191
locals : bindings. clone ( ) . map ( |b| GuardFrameLocal :: new ( b. var_id ) ) . collect ( ) ,
@@ -2402,6 +2325,82 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
2402
2325
}
2403
2326
}
2404
2327
2328
+ /// Binding for guards is a bit different from binding for the arm body,
2329
+ /// because an extra layer of implicit reference/dereference is added.
2330
+ ///
2331
+ /// The idea is that any pattern bindings of type T will map to a `&T` within
2332
+ /// the context of the guard expression, but will continue to map to a `T`
2333
+ /// in the context of the arm body. To avoid surfacing this distinction in
2334
+ /// the user source code (which would be a severe change to the language and
2335
+ /// require far more revision to the compiler), any occurrence of the
2336
+ /// identifier in the guard expression will automatically get a deref op
2337
+ /// applied to it. (See the caller of [`Self::is_bound_var_in_guard`].)
2338
+ ///
2339
+ /// So an input like:
2340
+ ///
2341
+ /// ```ignore (illustrative)
2342
+ /// let place = Foo::new();
2343
+ /// match place { foo if inspect(foo)
2344
+ /// => feed(foo), ... }
2345
+ /// ```
2346
+ ///
2347
+ /// will be treated as if it were really something like:
2348
+ ///
2349
+ /// ```ignore (illustrative)
2350
+ /// let place = Foo::new();
2351
+ /// match place { Foo { .. } if { let tmp1 = &place; inspect(*tmp1) }
2352
+ /// => { let tmp2 = place; feed(tmp2) }, ... }
2353
+ /// ```
2354
+ ///
2355
+ /// And an input like:
2356
+ ///
2357
+ /// ```ignore (illustrative)
2358
+ /// let place = Foo::new();
2359
+ /// match place { ref mut foo if inspect(foo)
2360
+ /// => feed(foo), ... }
2361
+ /// ```
2362
+ ///
2363
+ /// will be treated as if it were really something like:
2364
+ ///
2365
+ /// ```ignore (illustrative)
2366
+ /// let place = Foo::new();
2367
+ /// match place { Foo { .. } if { let tmp1 = & &mut place; inspect(*tmp1) }
2368
+ /// => { let tmp2 = &mut place; feed(tmp2) }, ... }
2369
+ /// ```
2370
+ /// ---
2371
+ ///
2372
+ /// ## Implementation notes
2373
+ ///
2374
+ /// To encode the distinction above, we must inject the
2375
+ /// temporaries `tmp1` and `tmp2`.
2376
+ ///
2377
+ /// There are two cases of interest: binding by-value, and binding by-ref.
2378
+ ///
2379
+ /// 1. Binding by-value: Things are simple.
2380
+ ///
2381
+ /// * Establishing `tmp1` creates a reference into the
2382
+ /// matched place. This code is emitted by
2383
+ /// [`Self::bind_matched_candidate_for_guard`].
2384
+ ///
2385
+ /// * `tmp2` is only initialized "lazily", after we have
2386
+ /// checked the guard. Thus, the code that can trigger
2387
+ /// moves out of the candidate can only fire after the
2388
+ /// guard evaluated to true. This initialization code is
2389
+ /// emitted by [`Self::bind_matched_candidate_for_arm_body`].
2390
+ ///
2391
+ /// 2. Binding by-reference: Things are tricky.
2392
+ ///
2393
+ /// * Here, the guard expression wants a `&&` or `&&mut`
2394
+ /// into the original input. This means we need to borrow
2395
+ /// the reference that we create for the arm.
2396
+ /// * So we eagerly create the reference for the arm and then take a
2397
+ /// reference to that.
2398
+ ///
2399
+ /// ---
2400
+ ///
2401
+ /// See these PRs for some historical context:
2402
+ /// - <https://github.com/rust-lang/rust/pull/49870> (introduction of autoref)
2403
+ /// - <https://github.com/rust-lang/rust/pull/59114> (always use autoref)
2405
2404
fn bind_matched_candidate_for_guard < ' b > (
2406
2405
& mut self ,
2407
2406
block : BasicBlock ,
@@ -2433,10 +2432,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
2433
2432
) ;
2434
2433
match binding. binding_mode . 0 {
2435
2434
ByRef :: No => {
2435
+ // The arm binding will be by value, so for the guard binding
2436
+ // just take a shared reference to the matched place.
2436
2437
let rvalue = Rvalue :: Ref ( re_erased, BorrowKind :: Shared , binding. source ) ;
2437
2438
self . cfg . push_assign ( block, source_info, ref_for_guard, rvalue) ;
2438
2439
}
2439
2440
ByRef :: Yes ( mutbl) => {
2441
+ // The arm binding will be by reference, so eagerly create it now.
2440
2442
let value_for_arm = self . storage_live_binding (
2441
2443
block,
2442
2444
binding. var_id ,
@@ -2448,6 +2450,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
2448
2450
let rvalue =
2449
2451
Rvalue :: Ref ( re_erased, util:: ref_pat_borrow_kind ( mutbl) , binding. source ) ;
2450
2452
self . cfg . push_assign ( block, source_info, value_for_arm, rvalue) ;
2453
+ // For the guard binding, take a shared reference to that reference.
2451
2454
let rvalue = Rvalue :: Ref ( re_erased, BorrowKind :: Shared , value_for_arm) ;
2452
2455
self . cfg . push_assign ( block, source_info, ref_for_guard, rvalue) ;
2453
2456
}
0 commit comments