@@ -2162,92 +2162,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
2162
2162
2163
2163
self . ascribe_types ( block, ascriptions) ;
2164
2164
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.
2246
2167
if let Some ( ( arm, match_scope) ) = arm_match_scope
2247
2168
&& let Some ( guard) = arm. guard
2248
2169
{
2249
2170
let tcx = self . tcx ;
2250
2171
2172
+ // Bindings for guards require some extra handling to automatically
2173
+ // insert implicit references/dereferences.
2251
2174
self . bind_matched_candidate_for_guard ( block, schedule_drops, bindings. clone ( ) ) ;
2252
2175
let guard_frame = GuardFrame {
2253
2176
locals : bindings. clone ( ) . map ( |b| GuardFrameLocal :: new ( b. var_id ) ) . collect ( ) ,
@@ -2387,6 +2310,82 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
2387
2310
}
2388
2311
}
2389
2312
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)
2390
2389
fn bind_matched_candidate_for_guard < ' b > (
2391
2390
& mut self ,
2392
2391
block : BasicBlock ,
@@ -2418,10 +2417,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
2418
2417
) ;
2419
2418
match binding. binding_mode . 0 {
2420
2419
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.
2421
2422
let rvalue = Rvalue :: Ref ( re_erased, BorrowKind :: Shared , binding. source ) ;
2422
2423
self . cfg . push_assign ( block, source_info, ref_for_guard, rvalue) ;
2423
2424
}
2424
2425
ByRef :: Yes ( mutbl) => {
2426
+ // The arm binding will be by reference, so eagerly create it now.
2425
2427
let value_for_arm = self . storage_live_binding (
2426
2428
block,
2427
2429
binding. var_id ,
@@ -2433,6 +2435,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
2433
2435
let rvalue =
2434
2436
Rvalue :: Ref ( re_erased, util:: ref_pat_borrow_kind ( mutbl) , binding. source ) ;
2435
2437
self . cfg . push_assign ( block, source_info, value_for_arm, rvalue) ;
2438
+ // For the guard binding, take a shared reference to that reference.
2436
2439
let rvalue = Rvalue :: Ref ( re_erased, BorrowKind :: Shared , value_for_arm) ;
2437
2440
self . cfg . push_assign ( block, source_info, ref_for_guard, rvalue) ;
2438
2441
}
0 commit comments