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

`}

`