Replace a long inline "autoref" comment with method docs · rust-lang/rust@83e1efb (original) (raw)
`@@ -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
`}
`