]>
Commit | Line | Data |
---|---|---|
9fa01778 XL |
1 | //! Code related to match expressions. These are sufficiently complex to |
2 | //! warrant their own module and submodules. :) This main module includes the | |
3 | //! high-level algorithm, the submodules contain the details. | |
4 | //! | |
5 | //! This also includes code for pattern bindings in `let` statements and | |
6 | //! function parameters. | |
7 | ||
6a06907d | 8 | use crate::build::expr::as_place::PlaceBuilder; |
dc9dc135 | 9 | use crate::build::scope::DropKind; |
9fa01778 XL |
10 | use crate::build::ForGuard::{self, OutsideGuard, RefWithinGuard}; |
11 | use crate::build::{BlockAnd, BlockAndExtension, Builder}; | |
12 | use crate::build::{GuardFrame, GuardFrameLocal, LocalsForNode}; | |
e8be2606 FG |
13 | use rustc_data_structures::{fx::FxIndexMap, stack::ensure_sufficient_stack}; |
14 | use rustc_hir::{BindingMode, ByRef}; | |
ba9703b0 | 15 | use rustc_middle::middle::region; |
c620b35d | 16 | use rustc_middle::mir::{self, *}; |
17df50a5 | 17 | use rustc_middle::thir::{self, *}; |
ba9703b0 | 18 | use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty}; |
f9f354fc | 19 | use rustc_span::symbol::Symbol; |
94222f64 | 20 | use rustc_span::{BytePos, Pos, Span}; |
ba9703b0 | 21 | use rustc_target::abi::VariantIdx; |
e9174d1e SL |
22 | // helper functions, broken out by category: |
23 | mod simplify; | |
24 | mod test; | |
25 | mod util; | |
26 | ||
74b04a01 | 27 | use std::borrow::Borrow; |
74b04a01 | 28 | use std::mem; |
0bf4aa26 | 29 | |
c620b35d FG |
30 | /// Arguments to [`Builder::then_else_break_inner`] that are usually forwarded |
31 | /// to recursive invocations. | |
32 | #[derive(Clone, Copy)] | |
33 | struct ThenElseArgs { | |
34 | /// Used as the temp scope for lowering `expr`. If absent (for match guards), | |
35 | /// `self.local_scope()` is used. | |
36 | temp_scope_override: Option<region::Scope>, | |
37 | variable_source_info: SourceInfo, | |
38 | /// Forwarded to [`Builder::lower_let_expr`] when lowering [`ExprKind::Let`]. | |
39 | /// When false (for match guards), `let` bindings won't be declared. | |
40 | declare_let_bindings: bool, | |
41 | } | |
42 | ||
dc9dc135 | 43 | impl<'a, 'tcx> Builder<'a, 'tcx> { |
c0240ec0 FG |
44 | /// Lowers a condition in a way that ensures that variables bound in any let |
45 | /// expressions are definitely initialized in the if body. | |
46 | /// | |
c620b35d | 47 | /// If `declare_let_bindings` is false then variables created in `let` |
c0240ec0 FG |
48 | /// expressions will not be declared. This is for if let guards on arms with |
49 | /// an or pattern, where the guard is lowered multiple times. | |
94222f64 XL |
50 | pub(crate) fn then_else_break( |
51 | &mut self, | |
c620b35d | 52 | block: BasicBlock, |
c0240ec0 | 53 | expr_id: ExprId, |
94222f64 | 54 | temp_scope_override: Option<region::Scope>, |
923072b8 | 55 | variable_source_info: SourceInfo, |
c620b35d FG |
56 | declare_let_bindings: bool, |
57 | ) -> BlockAnd<()> { | |
58 | self.then_else_break_inner( | |
59 | block, | |
60 | expr_id, | |
61 | ThenElseArgs { temp_scope_override, variable_source_info, declare_let_bindings }, | |
62 | ) | |
63 | } | |
64 | ||
65 | fn then_else_break_inner( | |
66 | &mut self, | |
67 | block: BasicBlock, // Block that the condition and branch will be lowered into | |
68 | expr_id: ExprId, // Condition expression to lower | |
69 | args: ThenElseArgs, | |
94222f64 XL |
70 | ) -> BlockAnd<()> { |
71 | let this = self; | |
c0240ec0 | 72 | let expr = &this.thir[expr_id]; |
94222f64 XL |
73 | let expr_span = expr.span; |
74 | ||
75 | match expr.kind { | |
5099ac24 | 76 | ExprKind::LogicalOp { op: LogicalOp::And, lhs, rhs } => { |
e8be2606 | 77 | this.visit_coverage_branch_operation(LogicalOp::And, expr_span); |
c620b35d FG |
78 | let lhs_then_block = unpack!(this.then_else_break_inner(block, lhs, args)); |
79 | let rhs_then_block = unpack!(this.then_else_break_inner(lhs_then_block, rhs, args)); | |
5099ac24 FG |
80 | rhs_then_block.unit() |
81 | } | |
781aab86 | 82 | ExprKind::LogicalOp { op: LogicalOp::Or, lhs, rhs } => { |
e8be2606 | 83 | this.visit_coverage_branch_operation(LogicalOp::Or, expr_span); |
781aab86 FG |
84 | let local_scope = this.local_scope(); |
85 | let (lhs_success_block, failure_block) = | |
86 | this.in_if_then_scope(local_scope, expr_span, |this| { | |
c620b35d | 87 | this.then_else_break_inner( |
781aab86 | 88 | block, |
c0240ec0 | 89 | lhs, |
c620b35d | 90 | ThenElseArgs { declare_let_bindings: true, ..args }, |
781aab86 FG |
91 | ) |
92 | }); | |
c620b35d | 93 | let rhs_success_block = unpack!(this.then_else_break_inner( |
781aab86 | 94 | failure_block, |
c0240ec0 | 95 | rhs, |
c620b35d | 96 | ThenElseArgs { declare_let_bindings: true, ..args }, |
781aab86 | 97 | )); |
c620b35d FG |
98 | |
99 | // Make the LHS and RHS success arms converge to a common block. | |
100 | // (We can't just make LHS goto RHS, because `rhs_success_block` | |
101 | // might contain statements that we don't want on the LHS path.) | |
102 | let success_block = this.cfg.start_new_block(); | |
103 | this.cfg.goto(lhs_success_block, args.variable_source_info, success_block); | |
104 | this.cfg.goto(rhs_success_block, args.variable_source_info, success_block); | |
105 | success_block.unit() | |
781aab86 FG |
106 | } |
107 | ExprKind::Unary { op: UnOp::Not, arg } => { | |
c620b35d FG |
108 | // Improve branch coverage instrumentation by noting conditions |
109 | // nested within one or more `!` expressions. | |
110 | // (Skipped if branch coverage is not enabled.) | |
111 | if let Some(branch_info) = this.coverage_branch_info.as_mut() { | |
112 | branch_info.visit_unary_not(this.thir, expr_id); | |
113 | } | |
114 | ||
781aab86 FG |
115 | let local_scope = this.local_scope(); |
116 | let (success_block, failure_block) = | |
117 | this.in_if_then_scope(local_scope, expr_span, |this| { | |
4b012472 FG |
118 | // Help out coverage instrumentation by injecting a dummy statement with |
119 | // the original condition's span (including `!`). This fixes #115468. | |
120 | if this.tcx.sess.instrument_coverage() { | |
121 | this.cfg.push_coverage_span_marker(block, this.source_info(expr_span)); | |
122 | } | |
c620b35d | 123 | this.then_else_break_inner( |
781aab86 | 124 | block, |
c0240ec0 | 125 | arg, |
c620b35d | 126 | ThenElseArgs { declare_let_bindings: true, ..args }, |
781aab86 FG |
127 | ) |
128 | }); | |
c620b35d | 129 | this.break_for_else(success_block, args.variable_source_info); |
781aab86 FG |
130 | failure_block.unit() |
131 | } | |
94222f64 XL |
132 | ExprKind::Scope { region_scope, lint_level, value } => { |
133 | let region_scope = (region_scope, this.source_info(expr_span)); | |
134 | this.in_scope(region_scope, lint_level, |this| { | |
c620b35d | 135 | this.then_else_break_inner(block, value, args) |
94222f64 XL |
136 | }) |
137 | } | |
c620b35d | 138 | ExprKind::Use { source } => this.then_else_break_inner(block, source, args), |
923072b8 FG |
139 | ExprKind::Let { expr, ref pat } => this.lower_let_expr( |
140 | block, | |
c0240ec0 | 141 | expr, |
923072b8 | 142 | pat, |
c620b35d FG |
143 | Some(args.variable_source_info.scope), |
144 | args.variable_source_info.span, | |
145 | args.declare_let_bindings, | |
923072b8 | 146 | ), |
94222f64 | 147 | _ => { |
c620b35d FG |
148 | let mut block = block; |
149 | let temp_scope = args.temp_scope_override.unwrap_or_else(|| this.local_scope()); | |
94222f64 XL |
150 | let mutability = Mutability::Mut; |
151 | let place = | |
c0240ec0 | 152 | unpack!(block = this.as_temp(block, Some(temp_scope), expr_id, mutability)); |
94222f64 XL |
153 | let operand = Operand::Move(Place::from(place)); |
154 | ||
155 | let then_block = this.cfg.start_new_block(); | |
156 | let else_block = this.cfg.start_new_block(); | |
9c376795 | 157 | let term = TerminatorKind::if_(operand, then_block, else_block); |
94222f64 | 158 | |
c620b35d FG |
159 | // Record branch coverage info for this condition. |
160 | // (Does nothing if branch coverage is not enabled.) | |
161 | this.visit_coverage_branch_condition(expr_id, then_block, else_block); | |
162 | ||
94222f64 XL |
163 | let source_info = this.source_info(expr_span); |
164 | this.cfg.terminate(block, source_info, term); | |
c620b35d | 165 | this.break_for_else(else_block, source_info); |
94222f64 XL |
166 | |
167 | then_block.unit() | |
168 | } | |
169 | } | |
170 | } | |
171 | ||
9fa01778 XL |
172 | /// Generates MIR for a `match` expression. |
173 | /// | |
174 | /// The MIR that we generate for a match looks like this. | |
175 | /// | |
176 | /// ```text | |
177 | /// [ 0. Pre-match ] | |
178 | /// | | |
179 | /// [ 1. Evaluate Scrutinee (expression being matched on) ] | |
ed00b5ec | 180 | /// [ (PlaceMention of scrutinee) ] |
9fa01778 XL |
181 | /// | |
182 | /// [ 2. Decision tree -- check discriminants ] <--------+ | |
183 | /// | | | |
184 | /// | (once a specific arm is chosen) | | |
185 | /// | | | |
186 | /// [pre_binding_block] [otherwise_block] | |
187 | /// | | | |
188 | /// [ 3. Create "guard bindings" for arm ] | | |
189 | /// [ (create fake borrows) ] | | |
190 | /// | | | |
191 | /// [ 4. Execute guard code ] | | |
192 | /// [ (read fake borrows) ] --(guard is false)-----------+ | |
193 | /// | | |
194 | /// | (guard results in true) | |
195 | /// | | |
196 | /// [ 5. Create real bindings and execute arm ] | |
197 | /// | | |
198 | /// [ Exit match ] | |
199 | /// ``` | |
200 | /// | |
201 | /// All of the different arms have been stacked on top of each other to | |
202 | /// simplify the diagram. For an arm with no guard the blocks marked 3 and | |
203 | /// 4 and the fake borrows are omitted. | |
204 | /// | |
205 | /// We generate MIR in the following steps: | |
206 | /// | |
ed00b5ec | 207 | /// 1. Evaluate the scrutinee and add the PlaceMention of it ([Builder::lower_scrutinee]). |
74b04a01 XL |
208 | /// 2. Create the decision tree ([Builder::lower_match_tree]). |
209 | /// 3. Determine the fake borrows that are needed from the places that were | |
dfeec247 | 210 | /// matched against and create the required temporaries for them |
e8be2606 | 211 | /// ([util::collect_fake_borrows]). |
74b04a01 | 212 | /// 4. Create everything else: the guards and the arms ([Builder::lower_match_arms]). |
9fa01778 XL |
213 | /// |
214 | /// ## False edges | |
215 | /// | |
e8be2606 FG |
216 | /// We don't want to have the exact structure of the decision tree be visible through borrow |
217 | /// checking. Specifically we want borrowck to think that: | |
218 | /// - at any point, any or none of the patterns and guards seen so far may have been tested; | |
219 | /// - after the match, any of the patterns may have matched. | |
9fa01778 | 220 | /// |
e8be2606 FG |
221 | /// For example, all of these would fail to error if borrowck could see the real CFG (examples |
222 | /// taken from `tests/ui/nll/match-cfg-fake-edges.rs`): | |
223 | /// ```ignore (too many errors, this is already in the test suite) | |
224 | /// let x = String::new(); | |
225 | /// let _ = match true { | |
226 | /// _ => {}, | |
227 | /// _ => drop(x), | |
228 | /// }; | |
229 | /// // Borrowck must not know the second arm is never run. | |
230 | /// drop(x); //~ ERROR use of moved value | |
231 | /// | |
232 | /// let x; | |
233 | /// # let y = true; | |
234 | /// match y { | |
235 | /// _ if { x = 2; true } => {}, | |
236 | /// // Borrowck must not know the guard is always run. | |
237 | /// _ => drop(x), //~ ERROR used binding `x` is possibly-uninitialized | |
238 | /// }; | |
239 | /// | |
240 | /// let x = String::new(); | |
241 | /// # let y = true; | |
242 | /// match y { | |
243 | /// false if { drop(x); true } => {}, | |
244 | /// // Borrowck must not know the guard is not run in the `true` case. | |
245 | /// true => drop(x), //~ ERROR use of moved value: `x` | |
246 | /// false => {}, | |
247 | /// }; | |
248 | /// | |
249 | /// # let mut y = (true, true); | |
250 | /// let r = &mut y.1; | |
251 | /// match y { | |
252 | /// //~^ ERROR cannot use `y.1` because it was mutably borrowed | |
253 | /// (false, true) => {} | |
254 | /// // Borrowck must not know we don't test `y.1` when `y.0` is `true`. | |
255 | /// (true, _) => drop(r), | |
256 | /// (false, _) => {} | |
257 | /// }; | |
258 | /// ``` | |
259 | /// | |
260 | /// We add false edges to act as if we were naively matching each arm in order. What we need is | |
261 | /// a (fake) path from each candidate to the next, specifically from candidate C's pre-binding | |
262 | /// block to next candidate D's pre-binding block. For maximum precision (needed for deref | |
263 | /// patterns), we choose the earliest node on D's success path that doesn't also lead to C (to | |
264 | /// avoid loops). | |
265 | /// | |
266 | /// This turns out to be easy to compute: that block is the `start_block` of the first call to | |
267 | /// `match_candidates` where D is the first candidate in the list. | |
268 | /// | |
269 | /// For example: | |
270 | /// ```rust | |
271 | /// # let (x, y) = (true, true); | |
272 | /// match (x, y) { | |
273 | /// (true, true) => 1, | |
274 | /// (false, true) => 2, | |
275 | /// (true, false) => 3, | |
276 | /// _ => 4, | |
277 | /// } | |
278 | /// # ; | |
279 | /// ``` | |
280 | /// In this example, the pre-binding block of arm 1 has a false edge to the block for result | |
281 | /// `false` of the first test on `x`. The other arms have false edges to the pre-binding blocks | |
282 | /// of the next arm. | |
283 | /// | |
284 | /// On top of this, we also add a false edge from the otherwise_block of each guard to the | |
285 | /// aforementioned start block of the next candidate, to ensure borrock doesn't rely on which | |
286 | /// guards may have run. | |
f2b60f7d | 287 | #[instrument(level = "debug", skip(self, arms))] |
923072b8 | 288 | pub(crate) fn match_expr( |
b7449926 | 289 | &mut self, |
ba9703b0 | 290 | destination: Place<'tcx>, |
b7449926 | 291 | mut block: BasicBlock, |
c0240ec0 | 292 | scrutinee_id: ExprId, |
17df50a5 | 293 | arms: &[ArmId], |
c0240ec0 FG |
294 | span: Span, |
295 | scrutinee_span: Span, | |
b7449926 | 296 | ) -> BlockAnd<()> { |
dfeec247 | 297 | let scrutinee_place = |
c0240ec0 | 298 | unpack!(block = self.lower_scrutinee(block, scrutinee_id, scrutinee_span)); |
ff7c6d11 | 299 | |
4b012472 | 300 | let mut arm_candidates = self.create_match_candidates(&scrutinee_place, arms); |
9fa01778 | 301 | |
f2b60f7d | 302 | let match_has_guard = arm_candidates.iter().any(|(_, candidate)| candidate.has_guard); |
74b04a01 XL |
303 | let mut candidates = |
304 | arm_candidates.iter_mut().map(|(_, candidate)| candidate).collect::<Vec<_>>(); | |
dfeec247 | 305 | |
c0240ec0 | 306 | let match_start_span = span.shrink_to_lo().to(scrutinee_span); |
94222f64 XL |
307 | |
308 | let fake_borrow_temps = self.lower_match_tree( | |
309 | block, | |
310 | scrutinee_span, | |
ed00b5ec | 311 | &scrutinee_place, |
94222f64 XL |
312 | match_start_span, |
313 | match_has_guard, | |
314 | &mut candidates, | |
315 | ); | |
dfeec247 XL |
316 | |
317 | self.lower_match_arms( | |
74b04a01 | 318 | destination, |
dfeec247 XL |
319 | scrutinee_place, |
320 | scrutinee_span, | |
321 | arm_candidates, | |
322 | self.source_info(span), | |
323 | fake_borrow_temps, | |
324 | ) | |
325 | } | |
9fa01778 | 326 | |
ed00b5ec | 327 | /// Evaluate the scrutinee and add the PlaceMention for it. |
dfeec247 XL |
328 | fn lower_scrutinee( |
329 | &mut self, | |
330 | mut block: BasicBlock, | |
c0240ec0 | 331 | scrutinee_id: ExprId, |
dfeec247 | 332 | scrutinee_span: Span, |
6a06907d | 333 | ) -> BlockAnd<PlaceBuilder<'tcx>> { |
c0240ec0 | 334 | let scrutinee_place_builder = unpack!(block = self.as_place_builder(block, scrutinee_id)); |
487cf647 | 335 | if let Some(scrutinee_place) = scrutinee_place_builder.try_to_place(self) { |
ed00b5ec FG |
336 | let source_info = self.source_info(scrutinee_span); |
337 | self.cfg.push_place_mention(block, source_info, scrutinee_place); | |
6a06907d XL |
338 | } |
339 | ||
340 | block.and(scrutinee_place_builder) | |
dfeec247 | 341 | } |
e9174d1e | 342 | |
dfeec247 XL |
343 | /// Create the initial `Candidate`s for a `match` expression. |
344 | fn create_match_candidates<'pat>( | |
345 | &mut self, | |
487cf647 | 346 | scrutinee: &PlaceBuilder<'tcx>, |
17df50a5 XL |
347 | arms: &'pat [ArmId], |
348 | ) -> Vec<(&'pat Arm<'tcx>, Candidate<'pat, 'tcx>)> | |
349 | where | |
350 | 'a: 'pat, | |
351 | { | |
9fa01778 XL |
352 | // Assemble a list of candidates: there is one candidate per pattern, |
353 | // which means there may be more than one candidate *per arm*. | |
dfeec247 | 354 | arms.iter() |
17df50a5 | 355 | .copied() |
9fa01778 | 356 | .map(|arm| { |
17df50a5 | 357 | let arm = &self.thir[arm]; |
9fa01778 | 358 | let arm_has_guard = arm.guard.is_some(); |
2b03887a FG |
359 | let arm_candidate = |
360 | Candidate::new(scrutinee.clone(), &arm.pattern, arm_has_guard, self); | |
74b04a01 | 361 | (arm, arm_candidate) |
9fa01778 | 362 | }) |
dfeec247 XL |
363 | .collect() |
364 | } | |
9fa01778 | 365 | |
dfeec247 XL |
366 | /// Create the decision tree for the match expression, starting from `block`. |
367 | /// | |
368 | /// Modifies `candidates` to store the bindings and type ascriptions for | |
369 | /// that candidate. | |
370 | /// | |
371 | /// Returns the places that need fake borrows because we bind or test them. | |
372 | fn lower_match_tree<'pat>( | |
373 | &mut self, | |
374 | block: BasicBlock, | |
375 | scrutinee_span: Span, | |
ed00b5ec | 376 | scrutinee_place_builder: &PlaceBuilder<'tcx>, |
94222f64 | 377 | match_start_span: Span, |
dfeec247 | 378 | match_has_guard: bool, |
74b04a01 | 379 | candidates: &mut [&mut Candidate<'pat, 'tcx>], |
e8be2606 FG |
380 | ) -> Vec<(Place<'tcx>, Local, FakeBorrowKind)> { |
381 | // The set of places that we are creating fake borrows of. If there are no match guards then | |
382 | // we don't need any fake borrows, so don't track them. | |
383 | let fake_borrows: Vec<(Place<'tcx>, Local, FakeBorrowKind)> = if match_has_guard { | |
384 | util::collect_fake_borrows( | |
385 | self, | |
386 | candidates, | |
387 | scrutinee_span, | |
388 | scrutinee_place_builder.base(), | |
389 | ) | |
390 | } else { | |
391 | Vec::new() | |
392 | }; | |
0bf4aa26 | 393 | |
e8be2606 FG |
394 | // See the doc comment on `match_candidates` for why we have an |
395 | // otherwise block. Match checking will ensure this is actually | |
396 | // unreachable. | |
c620b35d | 397 | let otherwise_block = self.cfg.start_new_block(); |
74b04a01 | 398 | |
dfeec247 | 399 | // This will generate code to test scrutinee_place and |
e9174d1e | 400 | // branch to the appropriate arm block |
c620b35d FG |
401 | self.match_candidates(match_start_span, scrutinee_span, block, otherwise_block, candidates); |
402 | ||
c620b35d FG |
403 | let source_info = self.source_info(scrutinee_span); |
404 | ||
405 | // Matching on a `scrutinee_place` with an uninhabited type doesn't | |
406 | // generate any memory reads by itself, and so if the place "expression" | |
407 | // contains unsafe operations like raw pointer dereferences or union | |
408 | // field projections, we wouldn't know to require an `unsafe` block | |
409 | // around a `match` equivalent to `std::intrinsics::unreachable()`. | |
410 | // See issue #47412 for this hole being discovered in the wild. | |
411 | // | |
412 | // HACK(eddyb) Work around the above issue by adding a dummy inspection | |
413 | // of `scrutinee_place`, specifically by applying `ReadForMatch`. | |
414 | // | |
415 | // NOTE: ReadForMatch also checks that the scrutinee is initialized. | |
416 | // This is currently needed to not allow matching on an uninitialized, | |
417 | // uninhabited value. If we get never patterns, those will check that | |
418 | // the place is initialized, and so this read would only be used to | |
419 | // check safety. | |
420 | let cause_matched_place = FakeReadCause::ForMatchedPlace(None); | |
ed00b5ec | 421 | |
c620b35d FG |
422 | if let Some(scrutinee_place) = scrutinee_place_builder.try_to_place(self) { |
423 | self.cfg.push_fake_read( | |
424 | otherwise_block, | |
425 | source_info, | |
426 | cause_matched_place, | |
427 | scrutinee_place, | |
428 | ); | |
74b04a01 XL |
429 | } |
430 | ||
c620b35d FG |
431 | self.cfg.terminate(otherwise_block, source_info, TerminatorKind::Unreachable); |
432 | ||
74b04a01 XL |
433 | // Link each leaf candidate to the `pre_binding_block` of the next one. |
434 | let mut previous_candidate: Option<&mut Candidate<'_, '_>> = None; | |
435 | ||
436 | for candidate in candidates { | |
437 | candidate.visit_leaves(|leaf_candidate| { | |
438 | if let Some(ref mut prev) = previous_candidate { | |
e8be2606 FG |
439 | assert!(leaf_candidate.false_edge_start_block.is_some()); |
440 | prev.next_candidate_start_block = leaf_candidate.false_edge_start_block; | |
74b04a01 XL |
441 | } |
442 | previous_candidate = Some(leaf_candidate); | |
443 | }); | |
444 | } | |
92a42be0 | 445 | |
e8be2606 | 446 | fake_borrows |
dfeec247 | 447 | } |
9fa01778 | 448 | |
dfeec247 XL |
449 | /// Lower the bindings, guards and arm bodies of a `match` expression. |
450 | /// | |
451 | /// The decision tree should have already been created | |
452 | /// (by [Builder::lower_match_tree]). | |
453 | /// | |
454 | /// `outer_source_info` is the SourceInfo for the whole match. | |
455 | fn lower_match_arms( | |
456 | &mut self, | |
ba9703b0 | 457 | destination: Place<'tcx>, |
6a06907d | 458 | scrutinee_place_builder: PlaceBuilder<'tcx>, |
dfeec247 | 459 | scrutinee_span: Span, |
17df50a5 | 460 | arm_candidates: Vec<(&'_ Arm<'tcx>, Candidate<'_, 'tcx>)>, |
dfeec247 | 461 | outer_source_info: SourceInfo, |
e8be2606 | 462 | fake_borrow_temps: Vec<(Place<'tcx>, Local, FakeBorrowKind)>, |
dfeec247 | 463 | ) -> BlockAnd<()> { |
dfeec247 XL |
464 | let arm_end_blocks: Vec<_> = arm_candidates |
465 | .into_iter() | |
74b04a01 | 466 | .map(|(arm, candidate)| { |
29967ef6 | 467 | debug!("lowering arm {:?}\ncandidate = {:?}", arm, candidate); |
dfeec247 XL |
468 | |
469 | let arm_source_info = self.source_info(arm.span); | |
470 | let arm_scope = (arm.scope, arm_source_info); | |
94222f64 | 471 | let match_scope = self.local_scope(); |
dfeec247 | 472 | self.in_scope(arm_scope, arm.lint_level, |this| { |
c0240ec0 FG |
473 | let old_dedup_scope = |
474 | mem::replace(&mut this.fixed_temps_scope, Some(arm.scope)); | |
475 | ||
487cf647 | 476 | // `try_to_place` may fail if it is unable to resolve the given |
6a06907d XL |
477 | // `PlaceBuilder` inside a closure. In this case, we don't want to include |
478 | // a scrutinee place. `scrutinee_place_builder` will fail to be resolved | |
479 | // if the only match arm is a wildcard (`_`). | |
480 | // Example: | |
481 | // ``` | |
482 | // let foo = (0, 1); | |
483 | // let c = || { | |
484 | // match foo { _ => () }; | |
485 | // }; | |
486 | // ``` | |
487cf647 FG |
487 | let scrutinee_place = scrutinee_place_builder.try_to_place(this); |
488 | let opt_scrutinee_place = | |
489 | scrutinee_place.as_ref().map(|place| (Some(place), scrutinee_span)); | |
dfeec247 XL |
490 | let scope = this.declare_bindings( |
491 | None, | |
492 | arm.span, | |
74b04a01 | 493 | &arm.pattern, |
c0240ec0 | 494 | arm.guard, |
6a06907d | 495 | opt_scrutinee_place, |
dfeec247 | 496 | ); |
9fa01778 | 497 | |
dfeec247 XL |
498 | let arm_block = this.bind_pattern( |
499 | outer_source_info, | |
74b04a01 | 500 | candidate, |
dc9dc135 XL |
501 | &fake_borrow_temps, |
502 | scrutinee_span, | |
487cf647 | 503 | Some((arm, match_scope)), |
f2b60f7d | 504 | false, |
dc9dc135 | 505 | ); |
9fa01778 | 506 | |
c0240ec0 FG |
507 | this.fixed_temps_scope = old_dedup_scope; |
508 | ||
dfeec247 XL |
509 | if let Some(source_scope) = scope { |
510 | this.source_scope = source_scope; | |
511 | } | |
9fa01778 | 512 | |
c0240ec0 | 513 | this.expr_into_dest(destination, arm_block, arm.body) |
dfeec247 | 514 | }) |
dc9dc135 | 515 | }) |
dfeec247 | 516 | .collect(); |
9fa01778 XL |
517 | |
518 | // all the arm blocks will rejoin here | |
519 | let end_block = self.cfg.start_new_block(); | |
520 | ||
94222f64 XL |
521 | let end_brace = self.source_info( |
522 | outer_source_info.span.with_lo(outer_source_info.span.hi() - BytePos::from_usize(1)), | |
523 | ); | |
9fa01778 | 524 | for arm_block in arm_end_blocks { |
94222f64 XL |
525 | let block = &self.cfg.basic_blocks[arm_block.0]; |
526 | let last_location = block.statements.last().map(|s| s.source_info); | |
527 | ||
528 | self.cfg.goto(unpack!(arm_block), last_location.unwrap_or(end_brace), end_block); | |
e9174d1e | 529 | } |
9fa01778 | 530 | |
94b46f34 | 531 | self.source_scope = outer_source_info.scope; |
e9174d1e SL |
532 | |
533 | end_block.unit() | |
534 | } | |
535 | ||
74b04a01 XL |
536 | /// Binds the variables and ascribes types for a given `match` arm or |
537 | /// `let` binding. | |
dfeec247 XL |
538 | /// |
539 | /// Also check if the guard matches, if it's provided. | |
74b04a01 XL |
540 | /// `arm_scope` should be `Some` if and only if this is called for a |
541 | /// `match` arm. | |
dfeec247 XL |
542 | fn bind_pattern( |
543 | &mut self, | |
544 | outer_source_info: SourceInfo, | |
74b04a01 | 545 | candidate: Candidate<'_, 'tcx>, |
e8be2606 | 546 | fake_borrow_temps: &[(Place<'tcx>, Local, FakeBorrowKind)], |
dfeec247 | 547 | scrutinee_span: Span, |
487cf647 | 548 | arm_match_scope: Option<(&Arm<'tcx>, region::Scope)>, |
f2b60f7d | 549 | storages_alive: bool, |
dfeec247 | 550 | ) -> BasicBlock { |
74b04a01 | 551 | if candidate.subcandidates.is_empty() { |
dfeec247 XL |
552 | // Avoid generating another `BasicBlock` when we only have one |
553 | // candidate. | |
554 | self.bind_and_guard_matched_candidate( | |
74b04a01 XL |
555 | candidate, |
556 | &[], | |
dfeec247 XL |
557 | fake_borrow_temps, |
558 | scrutinee_span, | |
487cf647 | 559 | arm_match_scope, |
74b04a01 | 560 | true, |
f2b60f7d | 561 | storages_alive, |
dfeec247 XL |
562 | ) |
563 | } else { | |
74b04a01 XL |
564 | // It's helpful to avoid scheduling drops multiple times to save |
565 | // drop elaboration from having to clean up the extra drops. | |
566 | // | |
567 | // If we are in a `let` then we only schedule drops for the first | |
568 | // candidate. | |
569 | // | |
570 | // If we're in a `match` arm then we could have a case like so: | |
571 | // | |
572 | // Ok(x) | Err(x) if return => { /* ... */ } | |
573 | // | |
574 | // In this case we don't want a drop of `x` scheduled when we | |
575 | // return: it isn't bound by move until right before enter the arm. | |
576 | // To handle this we instead unschedule it's drop after each time | |
577 | // we lower the guard. | |
578 | let target_block = self.cfg.start_new_block(); | |
579 | let mut schedule_drops = true; | |
487cf647 | 580 | let arm = arm_match_scope.unzip().0; |
5e7ed085 | 581 | // We keep a stack of all of the bindings and type ascriptions |
1b1a35ee | 582 | // from the parent candidates that we visit, that also need to |
74b04a01 XL |
583 | // be bound for each candidate. |
584 | traverse_candidate( | |
585 | candidate, | |
586 | &mut Vec::new(), | |
c620b35d | 587 | &mut |leaf_candidate, parent_data| { |
487cf647 FG |
588 | if let Some(arm) = arm { |
589 | self.clear_top_scope(arm.scope); | |
74b04a01 XL |
590 | } |
591 | let binding_end = self.bind_and_guard_matched_candidate( | |
592 | leaf_candidate, | |
c620b35d | 593 | parent_data, |
4b012472 | 594 | fake_borrow_temps, |
74b04a01 | 595 | scrutinee_span, |
487cf647 | 596 | arm_match_scope, |
74b04a01 | 597 | schedule_drops, |
f2b60f7d | 598 | storages_alive, |
74b04a01 | 599 | ); |
487cf647 | 600 | if arm.is_none() { |
74b04a01 XL |
601 | schedule_drops = false; |
602 | } | |
603 | self.cfg.goto(binding_end, outer_source_info, target_block); | |
604 | }, | |
c620b35d FG |
605 | |inner_candidate, parent_data| { |
606 | parent_data.push(inner_candidate.extra_data); | |
74b04a01 XL |
607 | inner_candidate.subcandidates.into_iter() |
608 | }, | |
c620b35d FG |
609 | |parent_data| { |
610 | parent_data.pop(); | |
74b04a01 XL |
611 | }, |
612 | ); | |
613 | ||
614 | target_block | |
dfeec247 XL |
615 | } |
616 | } | |
617 | ||
0bf4aa26 | 618 | pub(super) fn expr_into_pattern( |
b7449926 XL |
619 | &mut self, |
620 | mut block: BasicBlock, | |
f2b60f7d | 621 | irrefutable_pat: &Pat<'tcx>, |
c0240ec0 | 622 | initializer_id: ExprId, |
b7449926 | 623 | ) -> BlockAnd<()> { |
f2b60f7d | 624 | match irrefutable_pat.kind { |
b7449926 | 625 | // Optimize the case of `let x = ...` to write directly into `x` |
e8be2606 | 626 | PatKind::Binding { mode: BindingMode(ByRef::No, _), var, subpattern: None, .. } => { |
b7449926 | 627 | let place = |
74b04a01 | 628 | self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true); |
c0240ec0 | 629 | unpack!(block = self.expr_into_dest(place, block, initializer_id)); |
0bf4aa26 | 630 | |
0bf4aa26 XL |
631 | // Inject a fake read, see comments on `FakeReadCause::ForLet`. |
632 | let source_info = self.source_info(irrefutable_pat.span); | |
cdc7bbd5 | 633 | self.cfg.push_fake_read(block, source_info, FakeReadCause::ForLet(None), place); |
0bf4aa26 | 634 | |
b7449926 XL |
635 | self.schedule_drop_for_binding(var, irrefutable_pat.span, OutsideGuard); |
636 | block.unit() | |
637 | } | |
0531ce1d | 638 | |
b7449926 XL |
639 | // Optimize the case of `let x: T = ...` to write directly |
640 | // into `x` and then require that `T == typeof(x)`. | |
641 | // | |
642 | // Weirdly, this is needed to prevent the | |
643 | // `intrinsic-move-val.rs` test case from crashing. That | |
644 | // test works with uninitialized values in a rather | |
645 | // dubious way, so it may be that the test is kind of | |
646 | // broken. | |
e74abb32 | 647 | PatKind::AscribeUserType { |
dfeec247 | 648 | subpattern: |
f2b60f7d | 649 | box Pat { |
dfeec247 | 650 | kind: |
f2b60f7d | 651 | PatKind::Binding { |
e8be2606 FG |
652 | mode: BindingMode(ByRef::No, _), |
653 | var, | |
654 | subpattern: None, | |
655 | .. | |
dfeec247 | 656 | }, |
b7449926 XL |
657 | .. |
658 | }, | |
f2b60f7d | 659 | ascription: thir::Ascription { ref annotation, variance: _ }, |
b7449926 XL |
660 | } => { |
661 | let place = | |
74b04a01 | 662 | self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true); |
c0240ec0 | 663 | unpack!(block = self.expr_into_dest(place, block, initializer_id)); |
b7449926 | 664 | |
0bf4aa26 XL |
665 | // Inject a fake read, see comments on `FakeReadCause::ForLet`. |
666 | let pattern_source_info = self.source_info(irrefutable_pat.span); | |
cdc7bbd5 | 667 | let cause_let = FakeReadCause::ForLet(None); |
74b04a01 | 668 | self.cfg.push_fake_read(block, pattern_source_info, cause_let, place); |
0bf4aa26 | 669 | |
923072b8 FG |
670 | let ty_source_info = self.source_info(annotation.span); |
671 | ||
f2b60f7d | 672 | let base = self.canonical_user_type_annotations.push(annotation.clone()); |
0bf4aa26 XL |
673 | self.cfg.push( |
674 | block, | |
675 | Statement { | |
676 | source_info: ty_source_info, | |
b7449926 | 677 | kind: StatementKind::AscribeUserType( |
923072b8 | 678 | Box::new((place, UserTypeProjection { base, projs: Vec::new() })), |
0731742a XL |
679 | // We always use invariant as the variance here. This is because the |
680 | // variance field from the ascription refers to the variance to use | |
681 | // when applying the type to the value being matched, but this | |
682 | // ascription applies rather to the type of the binding. e.g., in this | |
683 | // example: | |
684 | // | |
685 | // ``` | |
686 | // let x: T = <expr> | |
687 | // ``` | |
688 | // | |
689 | // We are creating an ascription that defines the type of `x` to be | |
690 | // exactly `T` (i.e., with invariance). The variance field, in | |
691 | // contrast, is intended to be used to relate `T` to the type of | |
692 | // `<expr>`. | |
b7449926 | 693 | ty::Variance::Invariant, |
b7449926 XL |
694 | ), |
695 | }, | |
696 | ); | |
697 | ||
83c7162d | 698 | self.schedule_drop_for_binding(var, irrefutable_pat.span, OutsideGuard); |
8bb4bdeb XL |
699 | block.unit() |
700 | } | |
9fa01778 | 701 | |
8bb4bdeb | 702 | _ => { |
c0240ec0 | 703 | let initializer = &self.thir[initializer_id]; |
ed00b5ec | 704 | let place_builder = |
c0240ec0 | 705 | unpack!(block = self.lower_scrutinee(block, initializer_id, initializer.span)); |
4b012472 | 706 | self.place_into_pattern(block, irrefutable_pat, place_builder, true) |
e9174d1e | 707 | } |
e9174d1e | 708 | } |
e9174d1e SL |
709 | } |
710 | ||
923072b8 | 711 | pub(crate) fn place_into_pattern( |
b7449926 | 712 | &mut self, |
0731742a | 713 | block: BasicBlock, |
f2b60f7d | 714 | irrefutable_pat: &Pat<'tcx>, |
6a06907d | 715 | initializer: PlaceBuilder<'tcx>, |
b7449926 XL |
716 | set_match_place: bool, |
717 | ) -> BlockAnd<()> { | |
4b012472 | 718 | let mut candidate = Candidate::new(initializer.clone(), irrefutable_pat, false, self); |
94222f64 XL |
719 | let fake_borrow_temps = self.lower_match_tree( |
720 | block, | |
721 | irrefutable_pat.span, | |
ed00b5ec | 722 | &initializer, |
94222f64 XL |
723 | irrefutable_pat.span, |
724 | false, | |
725 | &mut [&mut candidate], | |
726 | ); | |
353b0b11 | 727 | |
74b04a01 | 728 | // For matches and function arguments, the place that is being matched |
8faf50e0 XL |
729 | // can be set when creating the variables. But the place for |
730 | // let PATTERN = ... might not even exist until we do the assignment. | |
74b04a01 | 731 | // so we set it here instead. |
8faf50e0 | 732 | if set_match_place { |
353b0b11 FG |
733 | let mut next = Some(&candidate); |
734 | while let Some(candidate_ref) = next.take() { | |
c620b35d | 735 | for binding in &candidate_ref.extra_data.bindings { |
74b04a01 | 736 | let local = self.var_local_id(binding.var_id, OutsideGuard); |
487cf647 | 737 | // `try_to_place` may fail if it is unable to resolve the given |
5099ac24 FG |
738 | // `PlaceBuilder` inside a closure. In this case, we don't want to include |
739 | // a scrutinee place. `scrutinee_place_builder` will fail for destructured | |
740 | // assignments. This is because a closure only captures the precise places | |
741 | // that it will read and as a result a closure may not capture the entire | |
742 | // tuple/struct and rather have individual places that will be read in the | |
743 | // final MIR. | |
744 | // Example: | |
745 | // ``` | |
746 | // let foo = (0, 1); | |
747 | // let c = || { | |
748 | // let (v1, v2) = foo; | |
749 | // }; | |
750 | // ``` | |
487cf647 | 751 | if let Some(place) = initializer.try_to_place(self) { |
add651ee FG |
752 | let LocalInfo::User(BindingForm::Var(VarBindingForm { |
753 | opt_match_place: Some((ref mut match_place, _)), | |
754 | .. | |
755 | })) = **self.local_decls[local].local_info.as_mut().assert_crate_local() | |
756 | else { | |
2b03887a FG |
757 | bug!("Let binding to non-user variable.") |
758 | }; | |
5099ac24 | 759 | *match_place = Some(place); |
74b04a01 | 760 | } |
8faf50e0 | 761 | } |
74b04a01 XL |
762 | // All of the subcandidates should bind the same locals, so we |
763 | // only visit the first one. | |
353b0b11 | 764 | next = candidate_ref.subcandidates.get(0) |
8faf50e0 XL |
765 | } |
766 | } | |
767 | ||
74b04a01 XL |
768 | self.bind_pattern( |
769 | self.source_info(irrefutable_pat.span), | |
770 | candidate, | |
c620b35d | 771 | fake_borrow_temps.as_slice(), |
74b04a01 XL |
772 | irrefutable_pat.span, |
773 | None, | |
f2b60f7d | 774 | false, |
74b04a01 XL |
775 | ) |
776 | .unit() | |
e9174d1e SL |
777 | } |
778 | ||
b7449926 XL |
779 | /// Declares the bindings of the given patterns and returns the visibility |
780 | /// scope for the bindings in these patterns, if such a scope had to be | |
781 | /// created. NOTE: Declaring the bindings should always be done in their | |
782 | /// drop scope. | |
2b03887a | 783 | #[instrument(skip(self), level = "debug")] |
923072b8 | 784 | pub(crate) fn declare_bindings( |
b7449926 XL |
785 | &mut self, |
786 | mut visibility_scope: Option<SourceScope>, | |
787 | scope_span: Span, | |
e74abb32 | 788 | pattern: &Pat<'tcx>, |
c0240ec0 | 789 | guard: Option<ExprId>, |
b7449926 XL |
790 | opt_match_place: Option<(Option<&Place<'tcx>>, Span)>, |
791 | ) -> Option<SourceScope> { | |
f9f354fc | 792 | self.visit_primary_bindings( |
4b012472 | 793 | pattern, |
0731742a | 794 | UserTypeProjections::none(), |
e8be2606 | 795 | &mut |this, name, mode, var, span, ty, user_ty| { |
b7449926 | 796 | if visibility_scope.is_none() { |
dc9dc135 | 797 | visibility_scope = |
e8be2606 | 798 | Some(this.new_source_scope(scope_span, LintLevel::Inherited)); |
ea8adc8c | 799 | } |
dc9dc135 | 800 | let source_info = SourceInfo { span, scope: this.source_scope }; |
b7449926 XL |
801 | let visibility_scope = visibility_scope.unwrap(); |
802 | this.declare_binding( | |
803 | source_info, | |
804 | visibility_scope, | |
b7449926 XL |
805 | name, |
806 | mode, | |
b7449926 XL |
807 | var, |
808 | ty, | |
809 | user_ty, | |
487cf647 | 810 | ArmHasGuard(guard.is_some()), |
b7449926 | 811 | opt_match_place.map(|(x, y)| (x.cloned(), y)), |
9fa01778 | 812 | pattern.span, |
b7449926 XL |
813 | ); |
814 | }, | |
815 | ); | |
c0240ec0 FG |
816 | if let Some(guard_expr) = guard { |
817 | self.declare_guard_bindings(guard_expr, scope_span, visibility_scope); | |
487cf647 | 818 | } |
94b46f34 | 819 | visibility_scope |
e9174d1e | 820 | } |
5bcae85e | 821 | |
c0240ec0 FG |
822 | /// Declare bindings in a guard. This has to be done when declaring bindings |
823 | /// for an arm to ensure that or patterns only have one version of each | |
824 | /// variable. | |
825 | pub(crate) fn declare_guard_bindings( | |
826 | &mut self, | |
827 | guard_expr: ExprId, | |
828 | scope_span: Span, | |
829 | visibility_scope: Option<SourceScope>, | |
830 | ) { | |
831 | match self.thir.exprs[guard_expr].kind { | |
832 | ExprKind::Let { expr: _, pat: ref guard_pat } => { | |
833 | // FIXME: pass a proper `opt_match_place` | |
834 | self.declare_bindings(visibility_scope, scope_span, guard_pat, None, None); | |
835 | } | |
836 | ExprKind::Scope { value, .. } => { | |
837 | self.declare_guard_bindings(value, scope_span, visibility_scope); | |
838 | } | |
839 | ExprKind::Use { source } => { | |
840 | self.declare_guard_bindings(source, scope_span, visibility_scope); | |
841 | } | |
842 | ExprKind::LogicalOp { op: LogicalOp::And, lhs, rhs } => { | |
843 | self.declare_guard_bindings(lhs, scope_span, visibility_scope); | |
844 | self.declare_guard_bindings(rhs, scope_span, visibility_scope); | |
845 | } | |
846 | _ => {} | |
847 | } | |
848 | } | |
849 | ||
923072b8 | 850 | pub(crate) fn storage_live_binding( |
b7449926 XL |
851 | &mut self, |
852 | block: BasicBlock, | |
923072b8 | 853 | var: LocalVarId, |
b7449926 XL |
854 | span: Span, |
855 | for_guard: ForGuard, | |
74b04a01 | 856 | schedule_drop: bool, |
b7449926 | 857 | ) -> Place<'tcx> { |
83c7162d | 858 | let local_id = self.var_local_id(var, for_guard); |
8bb4bdeb | 859 | let source_info = self.source_info(span); |
dfeec247 | 860 | self.cfg.push(block, Statement { source_info, kind: StatementKind::StorageLive(local_id) }); |
f2b60f7d | 861 | // Although there is almost always scope for given variable in corner cases |
04454e1e | 862 | // like #92893 we might get variable with no scope. |
ed00b5ec FG |
863 | if let Some(region_scope) = self.region_scope_tree.var_scope(var.0.local_id) |
864 | && schedule_drop | |
865 | { | |
74b04a01 XL |
866 | self.schedule_drop(span, region_scope, local_id, DropKind::Storage); |
867 | } | |
416331ca | 868 | Place::from(local_id) |
8bb4bdeb | 869 | } |
5bcae85e | 870 | |
923072b8 FG |
871 | pub(crate) fn schedule_drop_for_binding( |
872 | &mut self, | |
873 | var: LocalVarId, | |
874 | span: Span, | |
875 | for_guard: ForGuard, | |
876 | ) { | |
83c7162d | 877 | let local_id = self.var_local_id(var, for_guard); |
923072b8 | 878 | if let Some(region_scope) = self.region_scope_tree.var_scope(var.0.local_id) { |
04454e1e FG |
879 | self.schedule_drop(span, region_scope, local_id, DropKind::Value); |
880 | } | |
8bb4bdeb XL |
881 | } |
882 | ||
f9f354fc XL |
883 | /// Visit all of the primary bindings in a patterns, that is, visit the |
884 | /// leftmost occurrence of each variable bound in a pattern. A variable | |
885 | /// will occur more than once in an or-pattern. | |
886 | pub(super) fn visit_primary_bindings( | |
b7449926 | 887 | &mut self, |
e74abb32 | 888 | pattern: &Pat<'tcx>, |
532ac7d7 | 889 | pattern_user_ty: UserTypeProjections, |
b7449926 XL |
890 | f: &mut impl FnMut( |
891 | &mut Self, | |
f9f354fc | 892 | Symbol, |
b7449926 | 893 | BindingMode, |
923072b8 | 894 | LocalVarId, |
b7449926 XL |
895 | Span, |
896 | Ty<'tcx>, | |
532ac7d7 | 897 | UserTypeProjections, |
b7449926 XL |
898 | ), |
899 | ) { | |
f9f354fc XL |
900 | debug!( |
901 | "visit_primary_bindings: pattern={:?} pattern_user_ty={:?}", | |
902 | pattern, pattern_user_ty | |
903 | ); | |
f2b60f7d | 904 | match pattern.kind { |
e8be2606 | 905 | PatKind::Binding { name, mode, var, ty, ref subpattern, is_primary, .. } => { |
f9f354fc | 906 | if is_primary { |
e8be2606 | 907 | f(self, name, mode, var, pattern.span, ty, pattern_user_ty.clone()); |
f9f354fc | 908 | } |
5bcae85e | 909 | if let Some(subpattern) = subpattern.as_ref() { |
f9f354fc | 910 | self.visit_primary_bindings(subpattern, pattern_user_ty, f); |
5bcae85e SL |
911 | } |
912 | } | |
9fa01778 | 913 | |
dfeec247 XL |
914 | PatKind::Array { ref prefix, ref slice, ref suffix } |
915 | | PatKind::Slice { ref prefix, ref slice, ref suffix } => { | |
1b1a35ee XL |
916 | let from = u64::try_from(prefix.len()).unwrap(); |
917 | let to = u64::try_from(suffix.len()).unwrap(); | |
f2b60f7d | 918 | for subpattern in prefix.iter() { |
f9f354fc | 919 | self.visit_primary_bindings(subpattern, pattern_user_ty.clone().index(), f); |
0bf4aa26 XL |
920 | } |
921 | for subpattern in slice { | |
f9f354fc XL |
922 | self.visit_primary_bindings( |
923 | subpattern, | |
924 | pattern_user_ty.clone().subslice(from, to), | |
925 | f, | |
926 | ); | |
0bf4aa26 | 927 | } |
f2b60f7d | 928 | for subpattern in suffix.iter() { |
f9f354fc | 929 | self.visit_primary_bindings(subpattern, pattern_user_ty.clone().index(), f); |
5bcae85e SL |
930 | } |
931 | } | |
9fa01778 | 932 | |
ed00b5ec FG |
933 | PatKind::Constant { .. } |
934 | | PatKind::Range { .. } | |
935 | | PatKind::Wild | |
4b012472 | 936 | | PatKind::Never |
ed00b5ec | 937 | | PatKind::Error(_) => {} |
9fa01778 | 938 | |
e74abb32 | 939 | PatKind::Deref { ref subpattern } => { |
f9f354fc | 940 | self.visit_primary_bindings(subpattern, pattern_user_ty.deref(), f); |
5bcae85e | 941 | } |
9fa01778 | 942 | |
e8be2606 FG |
943 | PatKind::DerefPattern { ref subpattern, .. } => { |
944 | self.visit_primary_bindings(subpattern, UserTypeProjections::none(), f); | |
945 | } | |
946 | ||
e74abb32 | 947 | PatKind::AscribeUserType { |
0731742a | 948 | ref subpattern, |
923072b8 | 949 | ascription: thir::Ascription { ref annotation, variance: _ }, |
0731742a | 950 | } => { |
b7449926 XL |
951 | // This corresponds to something like |
952 | // | |
953 | // ``` | |
0bf4aa26 | 954 | // let A::<'a>(_): A<'static> = ...; |
b7449926 | 955 | // ``` |
0731742a XL |
956 | // |
957 | // Note that the variance doesn't apply here, as we are tracking the effect | |
958 | // of `user_ty` on any bindings contained with subpattern. | |
923072b8 | 959 | |
0731742a | 960 | let projection = UserTypeProjection { |
923072b8 | 961 | base: self.canonical_user_type_annotations.push(annotation.clone()), |
9fa01778 | 962 | projs: Vec::new(), |
0731742a | 963 | }; |
923072b8 FG |
964 | let subpattern_user_ty = |
965 | pattern_user_ty.push_projection(&projection, annotation.span); | |
f9f354fc | 966 | self.visit_primary_bindings(subpattern, subpattern_user_ty, f) |
b7449926 | 967 | } |
0bf4aa26 | 968 | |
ed00b5ec FG |
969 | PatKind::InlineConstant { ref subpattern, .. } => { |
970 | self.visit_primary_bindings(subpattern, pattern_user_ty, f) | |
971 | } | |
972 | ||
e74abb32 | 973 | PatKind::Leaf { ref subpatterns } => { |
5bcae85e | 974 | for subpattern in subpatterns { |
0731742a | 975 | let subpattern_user_ty = pattern_user_ty.clone().leaf(subpattern.field); |
f9f354fc XL |
976 | debug!("visit_primary_bindings: subpattern_user_ty={:?}", subpattern_user_ty); |
977 | self.visit_primary_bindings(&subpattern.pattern, subpattern_user_ty, f); | |
0bf4aa26 XL |
978 | } |
979 | } | |
980 | ||
add651ee | 981 | PatKind::Variant { adt_def, args: _, variant_index, ref subpatterns } => { |
0bf4aa26 | 982 | for subpattern in subpatterns { |
dfeec247 XL |
983 | let subpattern_user_ty = |
984 | pattern_user_ty.clone().variant(adt_def, variant_index, subpattern.field); | |
f9f354fc | 985 | self.visit_primary_bindings(&subpattern.pattern, subpattern_user_ty, f); |
5bcae85e SL |
986 | } |
987 | } | |
e74abb32 | 988 | PatKind::Or { ref pats } => { |
f9f354fc XL |
989 | // In cases where we recover from errors the primary bindings |
990 | // may not all be in the leftmost subpattern. For example in | |
991 | // `let (x | y) = ...`, the primary binding of `y` occurs in | |
992 | // the right subpattern | |
f2b60f7d | 993 | for subpattern in pats.iter() { |
f9f354fc XL |
994 | self.visit_primary_bindings(subpattern, pattern_user_ty.clone(), f); |
995 | } | |
e1599b0c | 996 | } |
5bcae85e SL |
997 | } |
998 | } | |
e9174d1e SL |
999 | } |
1000 | ||
c620b35d FG |
1001 | /// Data extracted from a pattern that doesn't affect which branch is taken. Collected during |
1002 | /// pattern simplification and not mutated later. | |
1003 | #[derive(Debug, Clone)] | |
1004 | struct PatternExtraData<'tcx> { | |
1005 | /// [`Span`] of the original pattern. | |
54a0048b SL |
1006 | span: Span, |
1007 | ||
c620b35d | 1008 | /// Bindings that must be established. |
b039eaaf | 1009 | bindings: Vec<Binding<'tcx>>, |
e9174d1e | 1010 | |
c620b35d | 1011 | /// Types that must be asserted. |
b7449926 | 1012 | ascriptions: Vec<Ascription<'tcx>>, |
c620b35d FG |
1013 | } |
1014 | ||
1015 | impl<'tcx> PatternExtraData<'tcx> { | |
1016 | fn is_empty(&self) -> bool { | |
1017 | self.bindings.is_empty() && self.ascriptions.is_empty() | |
1018 | } | |
1019 | } | |
1020 | ||
1021 | /// A pattern in a form suitable for generating code. | |
1022 | #[derive(Debug, Clone)] | |
1023 | struct FlatPat<'pat, 'tcx> { | |
1024 | /// To match the pattern, all of these must be satisfied... | |
1025 | // Invariant: all the `MatchPair`s are recursively simplified. | |
1026 | // Invariant: or-patterns must be sorted to the end. | |
1027 | match_pairs: Vec<MatchPair<'pat, 'tcx>>, | |
1028 | ||
1029 | extra_data: PatternExtraData<'tcx>, | |
1030 | } | |
1031 | ||
1032 | impl<'tcx, 'pat> FlatPat<'pat, 'tcx> { | |
1033 | fn new( | |
1034 | place: PlaceBuilder<'tcx>, | |
1035 | pattern: &'pat Pat<'tcx>, | |
1036 | cx: &mut Builder<'_, 'tcx>, | |
1037 | ) -> Self { | |
1038 | let mut flat_pat = FlatPat { | |
1039 | match_pairs: vec![MatchPair::new(place, pattern, cx)], | |
1040 | extra_data: PatternExtraData { | |
1041 | span: pattern.span, | |
1042 | bindings: Vec::new(), | |
1043 | ascriptions: Vec::new(), | |
1044 | }, | |
1045 | }; | |
1046 | cx.simplify_match_pairs(&mut flat_pat.match_pairs, &mut flat_pat.extra_data); | |
1047 | flat_pat | |
1048 | } | |
1049 | } | |
1050 | ||
1051 | #[derive(Debug)] | |
1052 | struct Candidate<'pat, 'tcx> { | |
1053 | /// For the candidate to match, all of these must be satisfied... | |
1054 | // Invariant: all the `MatchPair`s are recursively simplified. | |
1055 | // Invariant: or-patterns must be sorted at the end. | |
1056 | match_pairs: Vec<MatchPair<'pat, 'tcx>>, | |
b7449926 | 1057 | |
5869c6ff | 1058 | /// ...and if this is non-empty, one of these subcandidates also has to match... |
74b04a01 XL |
1059 | subcandidates: Vec<Candidate<'pat, 'tcx>>, |
1060 | ||
c620b35d FG |
1061 | /// ...and the guard must be evaluated if there is one. |
1062 | has_guard: bool, | |
1063 | ||
1064 | /// If the guard is `false` then branch to `otherwise_block`. | |
9fa01778 | 1065 | otherwise_block: Option<BasicBlock>, |
abe05a73 | 1066 | |
c620b35d FG |
1067 | /// If the candidate matches, bindings and ascriptions must be established. |
1068 | extra_data: PatternExtraData<'tcx>, | |
1069 | ||
e8be2606 FG |
1070 | /// If we filled `self.subcandidate`, we store here the span of the or-pattern they came from. |
1071 | // Invariant: it is `None` iff `subcandidates.is_empty()`. | |
1072 | or_span: Option<Span>, | |
1073 | ||
5869c6ff | 1074 | /// The block before the `bindings` have been established. |
74b04a01 | 1075 | pre_binding_block: Option<BasicBlock>, |
e8be2606 FG |
1076 | |
1077 | /// The earliest block that has only candidates >= this one as descendents. Used for false | |
1078 | /// edges, see the doc for [`Builder::match_expr`]. | |
1079 | false_edge_start_block: Option<BasicBlock>, | |
1080 | /// The `false_edge_start_block` of the next candidate. | |
1081 | next_candidate_start_block: Option<BasicBlock>, | |
e9174d1e SL |
1082 | } |
1083 | ||
74b04a01 | 1084 | impl<'tcx, 'pat> Candidate<'pat, 'tcx> { |
2b03887a FG |
1085 | fn new( |
1086 | place: PlaceBuilder<'tcx>, | |
1087 | pattern: &'pat Pat<'tcx>, | |
1088 | has_guard: bool, | |
c620b35d | 1089 | cx: &mut Builder<'_, 'tcx>, |
2b03887a | 1090 | ) -> Self { |
c620b35d FG |
1091 | Self::from_flat_pat(FlatPat::new(place, pattern, cx), has_guard) |
1092 | } | |
1093 | ||
1094 | fn from_flat_pat(flat_pat: FlatPat<'pat, 'tcx>, has_guard: bool) -> Self { | |
74b04a01 | 1095 | Candidate { |
c620b35d FG |
1096 | match_pairs: flat_pat.match_pairs, |
1097 | extra_data: flat_pat.extra_data, | |
74b04a01 | 1098 | has_guard, |
74b04a01 | 1099 | subcandidates: Vec::new(), |
e8be2606 | 1100 | or_span: None, |
74b04a01 XL |
1101 | otherwise_block: None, |
1102 | pre_binding_block: None, | |
e8be2606 FG |
1103 | false_edge_start_block: None, |
1104 | next_candidate_start_block: None, | |
74b04a01 XL |
1105 | } |
1106 | } | |
1107 | ||
1108 | /// Visit the leaf candidates (those with no subcandidates) contained in | |
1109 | /// this candidate. | |
1110 | fn visit_leaves<'a>(&'a mut self, mut visit_leaf: impl FnMut(&'a mut Self)) { | |
1111 | traverse_candidate( | |
1112 | self, | |
1113 | &mut (), | |
1114 | &mut move |c, _| visit_leaf(c), | |
1115 | move |c, _| c.subcandidates.iter_mut(), | |
1116 | |_| {}, | |
1117 | ); | |
1118 | } | |
1119 | } | |
1120 | ||
1121 | /// A depth-first traversal of the `Candidate` and all of its recursive | |
1122 | /// subcandidates. | |
1123 | fn traverse_candidate<'pat, 'tcx: 'pat, C, T, I>( | |
1124 | candidate: C, | |
1125 | context: &mut T, | |
1126 | visit_leaf: &mut impl FnMut(C, &mut T), | |
1127 | get_children: impl Copy + Fn(C, &mut T) -> I, | |
1128 | complete_children: impl Copy + Fn(&mut T), | |
1129 | ) where | |
1130 | C: Borrow<Candidate<'pat, 'tcx>>, | |
1131 | I: Iterator<Item = C>, | |
1132 | { | |
1133 | if candidate.borrow().subcandidates.is_empty() { | |
1134 | visit_leaf(candidate, context) | |
1135 | } else { | |
1136 | for child in get_children(candidate, context) { | |
1137 | traverse_candidate(child, context, visit_leaf, get_children, complete_children); | |
1138 | } | |
1139 | complete_children(context) | |
1140 | } | |
1141 | } | |
1142 | ||
e9174d1e | 1143 | #[derive(Clone, Debug)] |
b039eaaf SL |
1144 | struct Binding<'tcx> { |
1145 | span: Span, | |
ff7c6d11 | 1146 | source: Place<'tcx>, |
923072b8 | 1147 | var_id: LocalVarId, |
0731742a | 1148 | binding_mode: BindingMode, |
e9174d1e SL |
1149 | } |
1150 | ||
b7449926 XL |
1151 | /// Indicates that the type of `source` must be a subtype of the |
1152 | /// user-given type `user_ty`; this is basically a no-op but can | |
1153 | /// influence region inference. | |
1154 | #[derive(Clone, Debug)] | |
1155 | struct Ascription<'tcx> { | |
b7449926 | 1156 | source: Place<'tcx>, |
923072b8 | 1157 | annotation: CanonicalUserTypeAnnotation<'tcx>, |
0731742a | 1158 | variance: ty::Variance, |
b7449926 XL |
1159 | } |
1160 | ||
c620b35d FG |
1161 | #[derive(Debug, Clone)] |
1162 | enum TestCase<'pat, 'tcx> { | |
1163 | Irrefutable { binding: Option<Binding<'tcx>>, ascription: Option<Ascription<'tcx>> }, | |
1164 | Variant { adt_def: ty::AdtDef<'tcx>, variant_index: VariantIdx }, | |
1165 | Constant { value: mir::Const<'tcx> }, | |
1166 | Range(&'pat PatRange<'tcx>), | |
1167 | Slice { len: usize, variable_length: bool }, | |
e8be2606 | 1168 | Deref { temp: Place<'tcx>, mutability: Mutability }, |
c620b35d FG |
1169 | Or { pats: Box<[FlatPat<'pat, 'tcx>]> }, |
1170 | } | |
1171 | ||
1172 | impl<'pat, 'tcx> TestCase<'pat, 'tcx> { | |
1173 | fn as_range(&self) -> Option<&'pat PatRange<'tcx>> { | |
1174 | if let Self::Range(v) = self { Some(*v) } else { None } | |
1175 | } | |
1176 | } | |
1177 | ||
1178 | #[derive(Debug, Clone)] | |
923072b8 | 1179 | pub(crate) struct MatchPair<'pat, 'tcx> { |
c620b35d | 1180 | /// This place... |
e8be2606 FG |
1181 | // This can be `None` if it referred to a non-captured place in a closure. |
1182 | // Invariant: place.is_none() => test_case is Irrefutable | |
1183 | // In other words this must be `Some(_)` after simplification. | |
1184 | place: Option<Place<'tcx>>, | |
e9174d1e | 1185 | |
c620b35d FG |
1186 | /// ... must pass this test... |
1187 | // Invariant: after creation and simplification in `Candidate::new()`, this must not be | |
1188 | // `Irrefutable`. | |
1189 | test_case: TestCase<'pat, 'tcx>, | |
1190 | ||
1191 | /// ... and these subpairs must match. | |
1192 | subpairs: Vec<Self>, | |
1193 | ||
1194 | /// The pattern this was created from. | |
e74abb32 | 1195 | pattern: &'pat Pat<'tcx>, |
e9174d1e SL |
1196 | } |
1197 | ||
5869c6ff | 1198 | /// See [`Test`] for more. |
e9174d1e | 1199 | #[derive(Clone, Debug, PartialEq)] |
b039eaaf | 1200 | enum TestKind<'tcx> { |
5869c6ff | 1201 | /// Test what enum variant a value is. |
b039eaaf | 1202 | Switch { |
5869c6ff | 1203 | /// The enum type being tested. |
5e7ed085 | 1204 | adt_def: ty::AdtDef<'tcx>, |
b039eaaf | 1205 | }, |
e9174d1e | 1206 | |
c620b35d FG |
1207 | /// Test what value an integer or `char` has. |
1208 | SwitchInt, | |
1209 | ||
1210 | /// Test what value a `bool` has. | |
1211 | If, | |
92a42be0 | 1212 | |
dc9dc135 XL |
1213 | /// Test for equality with value, possibly after an unsizing coercion to |
1214 | /// `ty`, | |
b039eaaf | 1215 | Eq { |
781aab86 | 1216 | value: Const<'tcx>, |
dc9dc135 XL |
1217 | // Integer types are handled by `SwitchInt`, and constants with ADT |
1218 | // types are converted back into patterns, so this can only be `&str`, | |
1219 | // `&[T]`, `f32` or `f64`. | |
b039eaaf SL |
1220 | ty: Ty<'tcx>, |
1221 | }, | |
e9174d1e | 1222 | |
ed00b5ec | 1223 | /// Test whether the value falls within an inclusive or exclusive range. |
f2b60f7d | 1224 | Range(Box<PatRange<'tcx>>), |
e9174d1e | 1225 | |
5869c6ff | 1226 | /// Test that the length of the slice is equal to `len`. |
dfeec247 | 1227 | Len { len: u64, op: BinOp }, |
e8be2606 FG |
1228 | |
1229 | /// Call `Deref::deref[_mut]` on the value. | |
1230 | Deref { | |
1231 | /// Temporary to store the result of `deref()`/`deref_mut()`. | |
1232 | temp: Place<'tcx>, | |
1233 | mutability: Mutability, | |
1234 | }, | |
e9174d1e SL |
1235 | } |
1236 | ||
5869c6ff XL |
1237 | /// A test to perform to determine which [`Candidate`] matches a value. |
1238 | /// | |
1239 | /// [`Test`] is just the test to perform; it does not include the value | |
1240 | /// to be tested. | |
e9174d1e | 1241 | #[derive(Debug)] |
923072b8 | 1242 | pub(crate) struct Test<'tcx> { |
b039eaaf SL |
1243 | span: Span, |
1244 | kind: TestKind<'tcx>, | |
e9174d1e SL |
1245 | } |
1246 | ||
c620b35d FG |
1247 | /// The branch to be taken after a test. |
1248 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | |
1249 | enum TestBranch<'tcx> { | |
1250 | /// Success branch, used for tests with two possible outcomes. | |
1251 | Success, | |
1252 | /// Branch corresponding to this constant. | |
1253 | Constant(Const<'tcx>, u128), | |
1254 | /// Branch corresponding to this variant. | |
1255 | Variant(VariantIdx), | |
1256 | /// Failure branch for tests with two possible outcomes, and "otherwise" branch for other tests. | |
1257 | Failure, | |
1258 | } | |
1259 | ||
1260 | impl<'tcx> TestBranch<'tcx> { | |
1261 | fn as_constant(&self) -> Option<&Const<'tcx>> { | |
1262 | if let Self::Constant(v, _) = self { Some(v) } else { None } | |
1263 | } | |
1264 | } | |
1265 | ||
5869c6ff | 1266 | /// `ArmHasGuard` is a wrapper around a boolean flag. It indicates whether |
9fa01778 XL |
1267 | /// a match arm has a guard expression attached to it. |
1268 | #[derive(Copy, Clone, Debug)] | |
923072b8 | 1269 | pub(crate) struct ArmHasGuard(pub(crate) bool); |
9fa01778 | 1270 | |
e9174d1e SL |
1271 | /////////////////////////////////////////////////////////////////////////// |
1272 | // Main matching algorithm | |
1273 | ||
dc9dc135 | 1274 | impl<'a, 'tcx> Builder<'a, 'tcx> { |
92a42be0 SL |
1275 | /// The main match algorithm. It begins with a set of candidates |
1276 | /// `candidates` and has the job of generating code to determine | |
1277 | /// which of these candidates, if any, is the correct one. The | |
9cc50fc6 SL |
1278 | /// candidates are sorted such that the first item in the list |
1279 | /// has the highest priority. When a candidate is found to match | |
74b04a01 | 1280 | /// the value, we will set and generate a branch to the appropriate |
5869c6ff | 1281 | /// pre-binding block. |
92a42be0 | 1282 | /// |
c620b35d | 1283 | /// If we find that *NONE* of the candidates apply, we branch to `otherwise_block`. |
92a42be0 | 1284 | /// |
5869c6ff | 1285 | /// It might be surprising that the input can be non-exhaustive. |
92a42be0 SL |
1286 | /// Indeed, initially, it is not, because all matches are |
1287 | /// exhaustive in Rust. But during processing we sometimes divide | |
1288 | /// up the list of candidates and recurse with a non-exhaustive | |
c620b35d FG |
1289 | /// list. This is how our lowering approach (called "backtracking |
1290 | /// automaton" in the literature) works. | |
1291 | /// See [`Builder::test_candidates`] for more details. | |
0bf4aa26 | 1292 | /// |
5869c6ff | 1293 | /// If `fake_borrows` is `Some`, then places which need fake borrows |
0bf4aa26 | 1294 | /// will be added to it. |
74b04a01 | 1295 | /// |
c620b35d | 1296 | /// For an example of how we use `otherwise_block`, consider: |
5869c6ff | 1297 | /// ``` |
c620b35d FG |
1298 | /// # fn foo((x, y): (bool, bool)) -> u32 { |
1299 | /// match (x, y) { | |
1300 | /// (true, true) => 1, | |
1301 | /// (_, false) => 2, | |
1302 | /// (false, true) => 3, | |
74b04a01 | 1303 | /// } |
04454e1e | 1304 | /// # } |
fc512014 | 1305 | /// ``` |
c620b35d FG |
1306 | /// For this match, we generate something like: |
1307 | /// ``` | |
1308 | /// # fn foo((x, y): (bool, bool)) -> u32 { | |
1309 | /// if x { | |
1310 | /// if y { | |
1311 | /// return 1 | |
1312 | /// } else { | |
1313 | /// // continue | |
1314 | /// } | |
1315 | /// } else { | |
1316 | /// // continue | |
1317 | /// } | |
1318 | /// if y { | |
1319 | /// if x { | |
1320 | /// // This is actually unreachable because the `(true, true)` case was handled above. | |
1321 | /// // continue | |
1322 | /// } else { | |
1323 | /// return 3 | |
1324 | /// } | |
1325 | /// } else { | |
1326 | /// return 2 | |
1327 | /// } | |
1328 | /// // this is the final `otherwise_block`, which is unreachable because the match was exhaustive. | |
1329 | /// unreachable!() | |
1330 | /// # } | |
1331 | /// ``` | |
1332 | /// | |
1333 | /// Every `continue` is an instance of branching to some `otherwise_block` somewhere deep within | |
1334 | /// the algorithm. For more details on why we lower like this, see [`Builder::test_candidates`]. | |
74b04a01 | 1335 | /// |
c620b35d FG |
1336 | /// Note how we test `x` twice. This is the tradeoff of backtracking automata: we prefer smaller |
1337 | /// code size at the expense of non-optimal code paths. | |
1338 | #[instrument(skip(self), level = "debug")] | |
b7449926 XL |
1339 | fn match_candidates<'pat>( |
1340 | &mut self, | |
1341 | span: Span, | |
94222f64 | 1342 | scrutinee_span: Span, |
74b04a01 | 1343 | start_block: BasicBlock, |
c620b35d | 1344 | otherwise_block: BasicBlock, |
9fa01778 | 1345 | candidates: &mut [&mut Candidate<'pat, 'tcx>], |
dc9dc135 | 1346 | ) { |
74b04a01 | 1347 | let mut split_or_candidate = false; |
9fa01778 | 1348 | for candidate in &mut *candidates { |
e8be2606 | 1349 | if let [MatchPair { test_case: TestCase::Or { .. }, .. }] = &*candidate.match_pairs { |
c620b35d FG |
1350 | // Split a candidate in which the only match-pair is an or-pattern into multiple |
1351 | // candidates. This is so that | |
1352 | // | |
1353 | // match x { | |
1354 | // 0 | 1 => { ... }, | |
1355 | // 2 | 3 => { ... }, | |
1356 | // } | |
1357 | // | |
1358 | // only generates a single switch. | |
e8be2606 FG |
1359 | let match_pair = candidate.match_pairs.pop().unwrap(); |
1360 | self.create_or_subcandidates(candidate, match_pair); | |
c620b35d FG |
1361 | split_or_candidate = true; |
1362 | } | |
e9174d1e SL |
1363 | } |
1364 | ||
f9f354fc XL |
1365 | ensure_sufficient_stack(|| { |
1366 | if split_or_candidate { | |
1367 | // At least one of the candidates has been split into subcandidates. | |
1368 | // We need to change the candidate list to include those. | |
1369 | let mut new_candidates = Vec::new(); | |
e8be2606 | 1370 | for candidate in candidates.iter_mut() { |
f9f354fc XL |
1371 | candidate.visit_leaves(|leaf_candidate| new_candidates.push(leaf_candidate)); |
1372 | } | |
e8be2606 | 1373 | self.match_candidates( |
f9f354fc | 1374 | span, |
94222f64 | 1375 | scrutinee_span, |
f9f354fc XL |
1376 | start_block, |
1377 | otherwise_block, | |
1378 | &mut *new_candidates, | |
f9f354fc | 1379 | ); |
e8be2606 FG |
1380 | |
1381 | for candidate in candidates { | |
1382 | self.merge_trivial_subcandidates(candidate); | |
1383 | } | |
f9f354fc XL |
1384 | } else { |
1385 | self.match_simplified_candidates( | |
1386 | span, | |
94222f64 | 1387 | scrutinee_span, |
f9f354fc XL |
1388 | start_block, |
1389 | otherwise_block, | |
1390 | candidates, | |
f9f354fc | 1391 | ); |
74b04a01 | 1392 | } |
f9f354fc | 1393 | }); |
74b04a01 XL |
1394 | } |
1395 | ||
1396 | fn match_simplified_candidates( | |
1397 | &mut self, | |
1398 | span: Span, | |
94222f64 | 1399 | scrutinee_span: Span, |
c620b35d FG |
1400 | mut start_block: BasicBlock, |
1401 | otherwise_block: BasicBlock, | |
74b04a01 | 1402 | candidates: &mut [&mut Candidate<'_, 'tcx>], |
74b04a01 | 1403 | ) { |
e8be2606 FG |
1404 | if let [first, ..] = candidates { |
1405 | if first.false_edge_start_block.is_none() { | |
1406 | first.false_edge_start_block = Some(start_block); | |
1407 | } | |
1408 | } | |
1409 | ||
c620b35d FG |
1410 | match candidates { |
1411 | [] => { | |
1412 | // If there are no candidates that still need testing, we're done. Since all matches are | |
1413 | // exhaustive, execution should never reach this point. | |
1414 | let source_info = self.source_info(span); | |
1415 | self.cfg.goto(start_block, source_info, otherwise_block); | |
dfeec247 | 1416 | } |
c620b35d FG |
1417 | [first, remaining @ ..] if first.match_pairs.is_empty() => { |
1418 | // The first candidate has satisfied all its match pairs; we link it up and continue | |
1419 | // with the remaining candidates. | |
1420 | start_block = self.select_matched_candidate(first, start_block); | |
1421 | self.match_simplified_candidates( | |
1422 | span, | |
1423 | scrutinee_span, | |
1424 | start_block, | |
1425 | otherwise_block, | |
1426 | remaining, | |
1427 | ) | |
1428 | } | |
1429 | candidates => { | |
1430 | // The first candidate has some unsatisfied match pairs; we proceed to do more tests. | |
1431 | self.test_candidates_with_or( | |
1432 | span, | |
1433 | scrutinee_span, | |
1434 | candidates, | |
1435 | start_block, | |
1436 | otherwise_block, | |
1437 | ); | |
dc9dc135 | 1438 | } |
92a42be0 | 1439 | } |
9fa01778 XL |
1440 | } |
1441 | ||
5869c6ff XL |
1442 | /// Link up matched candidates. |
1443 | /// | |
1444 | /// For example, if we have something like this: | |
9fa01778 | 1445 | /// |
04454e1e | 1446 | /// ```ignore (illustrative) |
9fa01778 | 1447 | /// ... |
5869c6ff | 1448 | /// Some(x) if cond1 => ... |
9fa01778 | 1449 | /// Some(x) => ... |
5869c6ff | 1450 | /// Some(x) if cond2 => ... |
9fa01778 | 1451 | /// ... |
fc512014 | 1452 | /// ``` |
9fa01778 XL |
1453 | /// |
1454 | /// We generate real edges from: | |
9fa01778 | 1455 | /// |
5869c6ff XL |
1456 | /// * `start_block` to the [pre-binding block] of the first pattern, |
1457 | /// * the [otherwise block] of the first pattern to the second pattern, | |
1458 | /// * the [otherwise block] of the third pattern to a block with an | |
1459 | /// [`Unreachable` terminator](TerminatorKind::Unreachable). | |
1460 | /// | |
c620b35d | 1461 | /// In addition, we later add fake edges from the otherwise blocks to the |
5869c6ff | 1462 | /// pre-binding block of the next candidate in the original set of |
9fa01778 | 1463 | /// candidates. |
5869c6ff XL |
1464 | /// |
1465 | /// [pre-binding block]: Candidate::pre_binding_block | |
1466 | /// [otherwise block]: Candidate::otherwise_block | |
c620b35d | 1467 | fn select_matched_candidate( |
9fa01778 | 1468 | &mut self, |
c620b35d | 1469 | candidate: &mut Candidate<'_, 'tcx>, |
74b04a01 | 1470 | start_block: BasicBlock, |
c620b35d FG |
1471 | ) -> BasicBlock { |
1472 | assert!(candidate.otherwise_block.is_none()); | |
1473 | assert!(candidate.pre_binding_block.is_none()); | |
1474 | assert!(candidate.subcandidates.is_empty()); | |
1475 | ||
1476 | candidate.pre_binding_block = Some(start_block); | |
1477 | let otherwise_block = self.cfg.start_new_block(); | |
1478 | if candidate.has_guard { | |
1479 | // Create the otherwise block for this candidate, which is the | |
1480 | // pre-binding block for the next candidate. | |
1481 | candidate.otherwise_block = Some(otherwise_block); | |
74b04a01 | 1482 | } |
c620b35d | 1483 | otherwise_block |
74b04a01 XL |
1484 | } |
1485 | ||
1486 | /// Tests a candidate where there are only or-patterns left to test, or | |
1487 | /// forwards to [Builder::test_candidates]. | |
1488 | /// | |
1489 | /// Given a pattern `(P | Q, R | S)` we (in principle) generate a CFG like | |
5869c6ff | 1490 | /// so: |
74b04a01 XL |
1491 | /// |
1492 | /// ```text | |
1493 | /// [ start ] | |
1494 | /// | | |
1495 | /// [ match P, Q ] | |
1496 | /// | | |
1497 | /// +----------------------------------------+------------------------------------+ | |
1498 | /// | | | | |
1499 | /// V V V | |
1500 | /// [ P matches ] [ Q matches ] [ otherwise ] | |
1501 | /// | | | | |
1502 | /// V V | | |
1503 | /// [ match R, S ] [ match R, S ] | | |
1504 | /// | | | | |
1505 | /// +--------------+------------+ +--------------+------------+ | | |
1506 | /// | | | | | | | | |
1507 | /// V V V V V V | | |
1508 | /// [ R matches ] [ S matches ] [otherwise ] [ R matches ] [ S matches ] [otherwise ] | | |
1509 | /// | | | | | | | | |
1510 | /// +--------------+------------|------------+--------------+ | | | |
1511 | /// | | | | | |
1512 | /// | +----------------------------------------+--------+ | |
1513 | /// | | | |
1514 | /// V V | |
1515 | /// [ Success ] [ Failure ] | |
1516 | /// ``` | |
1517 | /// | |
1518 | /// In practice there are some complications: | |
1519 | /// | |
1520 | /// * If there's a guard, then the otherwise branch of the first match on | |
1521 | /// `R | S` goes to a test for whether `Q` matches, and the control flow | |
1522 | /// doesn't merge into a single success block until after the guard is | |
1523 | /// tested. | |
1524 | /// * If neither `P` or `Q` has any bindings or type ascriptions and there | |
1525 | /// isn't a match guard, then we create a smaller CFG like: | |
1526 | /// | |
1527 | /// ```text | |
1528 | /// ... | |
1529 | /// +---------------+------------+ | |
1530 | /// | | | | |
1531 | /// [ P matches ] [ Q matches ] [ otherwise ] | |
1532 | /// | | | | |
1533 | /// +---------------+ | | |
1534 | /// | ... | |
1535 | /// [ match R, S ] | |
1536 | /// | | |
1537 | /// ... | |
1538 | /// ``` | |
1539 | fn test_candidates_with_or( | |
1540 | &mut self, | |
1541 | span: Span, | |
94222f64 | 1542 | scrutinee_span: Span, |
74b04a01 | 1543 | candidates: &mut [&mut Candidate<'_, 'tcx>], |
c620b35d FG |
1544 | start_block: BasicBlock, |
1545 | otherwise_block: BasicBlock, | |
74b04a01 XL |
1546 | ) { |
1547 | let (first_candidate, remaining_candidates) = candidates.split_first_mut().unwrap(); | |
c620b35d FG |
1548 | assert!(first_candidate.subcandidates.is_empty()); |
1549 | if !matches!(first_candidate.match_pairs[0].test_case, TestCase::Or { .. }) { | |
1550 | self.test_candidates(span, scrutinee_span, candidates, start_block, otherwise_block); | |
1551 | return; | |
9fa01778 XL |
1552 | } |
1553 | ||
e8be2606 FG |
1554 | let first_match_pair = first_candidate.match_pairs.remove(0); |
1555 | let remaining_match_pairs = mem::take(&mut first_candidate.match_pairs); | |
c620b35d | 1556 | let remainder_start = self.cfg.start_new_block(); |
c620b35d | 1557 | // Test the alternatives of this or-pattern. |
e8be2606 | 1558 | self.test_or_pattern(first_candidate, start_block, remainder_start, first_match_pair); |
c620b35d FG |
1559 | |
1560 | if !remaining_match_pairs.is_empty() { | |
1561 | // If more match pairs remain, test them after each subcandidate. | |
1562 | // We could add them to the or-candidates before the call to `test_or_pattern` but this | |
1563 | // would make it impossible to detect simplifiable or-patterns. That would guarantee | |
1564 | // exponentially large CFGs for cases like `(1 | 2, 3 | 4, ...)`. | |
5099ac24 | 1565 | first_candidate.visit_leaves(|leaf_candidate| { |
c620b35d FG |
1566 | assert!(leaf_candidate.match_pairs.is_empty()); |
1567 | leaf_candidate.match_pairs.extend(remaining_match_pairs.iter().cloned()); | |
1568 | let or_start = leaf_candidate.pre_binding_block.unwrap(); | |
1569 | // In a case like `(a | b, c | d)`, if `a` succeeds and `c | d` fails, we know `(b, | |
1570 | // c | d)` will fail too. If there is no guard, we skip testing of `b` by branching | |
1571 | // directly to `remainder_start`. If there is a guard, we have to try `(b, c | d)`. | |
1572 | let or_otherwise = leaf_candidate.otherwise_block.unwrap_or(remainder_start); | |
1573 | self.test_candidates_with_or( | |
1574 | span, | |
1575 | scrutinee_span, | |
1576 | &mut [leaf_candidate], | |
1577 | or_start, | |
1578 | or_otherwise, | |
5099ac24 FG |
1579 | ); |
1580 | }); | |
9fa01778 XL |
1581 | } |
1582 | ||
c620b35d | 1583 | // Test the remaining candidates. |
74b04a01 XL |
1584 | self.match_candidates( |
1585 | span, | |
94222f64 | 1586 | scrutinee_span, |
74b04a01 XL |
1587 | remainder_start, |
1588 | otherwise_block, | |
1589 | remaining_candidates, | |
c620b35d | 1590 | ); |
74b04a01 XL |
1591 | } |
1592 | ||
e8be2606 | 1593 | #[instrument(skip(self, start_block, otherwise_block, candidate, match_pair), level = "debug")] |
74b04a01 XL |
1594 | fn test_or_pattern<'pat>( |
1595 | &mut self, | |
1596 | candidate: &mut Candidate<'pat, 'tcx>, | |
c620b35d FG |
1597 | start_block: BasicBlock, |
1598 | otherwise_block: BasicBlock, | |
e8be2606 | 1599 | match_pair: MatchPair<'pat, 'tcx>, |
74b04a01 | 1600 | ) { |
e8be2606 FG |
1601 | let or_span = match_pair.pattern.span; |
1602 | self.create_or_subcandidates(candidate, match_pair); | |
1603 | let mut or_candidate_refs: Vec<_> = candidate.subcandidates.iter_mut().collect(); | |
74b04a01 | 1604 | self.match_candidates( |
94222f64 | 1605 | or_span, |
74b04a01 | 1606 | or_span, |
c620b35d FG |
1607 | start_block, |
1608 | otherwise_block, | |
74b04a01 | 1609 | &mut or_candidate_refs, |
74b04a01 | 1610 | ); |
e8be2606 | 1611 | self.merge_trivial_subcandidates(candidate); |
74b04a01 XL |
1612 | } |
1613 | ||
e8be2606 FG |
1614 | /// Given a match-pair that corresponds to an or-pattern, expand each subpattern into a new |
1615 | /// subcandidate. Any candidate that has been expanded that way should be passed to | |
1616 | /// `merge_trivial_subcandidates` after its subcandidates have been processed. | |
1617 | fn create_or_subcandidates<'pat>( | |
74b04a01 | 1618 | &mut self, |
e8be2606 FG |
1619 | candidate: &mut Candidate<'pat, 'tcx>, |
1620 | match_pair: MatchPair<'pat, 'tcx>, | |
74b04a01 | 1621 | ) { |
e8be2606 FG |
1622 | let TestCase::Or { pats } = match_pair.test_case else { bug!() }; |
1623 | debug!("expanding or-pattern: candidate={:#?}\npats={:#?}", candidate, pats); | |
1624 | candidate.or_span = Some(match_pair.pattern.span); | |
1625 | candidate.subcandidates = pats | |
1626 | .into_vec() | |
1627 | .into_iter() | |
1628 | .map(|flat_pat| Candidate::from_flat_pat(flat_pat, candidate.has_guard)) | |
1629 | .collect(); | |
1630 | candidate.subcandidates[0].false_edge_start_block = candidate.false_edge_start_block; | |
1631 | } | |
1632 | ||
1633 | /// Try to merge all of the subcandidates of the given candidate into one. This avoids | |
1634 | /// exponentially large CFGs in cases like `(1 | 2, 3 | 4, ...)`. The or-pattern should have | |
1635 | /// been expanded with `create_or_subcandidates`. | |
1636 | fn merge_trivial_subcandidates(&mut self, candidate: &mut Candidate<'_, 'tcx>) { | |
74b04a01 XL |
1637 | if candidate.subcandidates.is_empty() || candidate.has_guard { |
1638 | // FIXME(or_patterns; matthewjasper) Don't give up if we have a guard. | |
1639 | return; | |
1640 | } | |
1641 | ||
e8be2606 FG |
1642 | // FIXME(or_patterns; matthewjasper) Try to be more aggressive here. |
1643 | let can_merge = candidate.subcandidates.iter().all(|subcandidate| { | |
1644 | subcandidate.subcandidates.is_empty() && subcandidate.extra_data.is_empty() | |
1645 | }); | |
74b04a01 XL |
1646 | if can_merge { |
1647 | let any_matches = self.cfg.start_new_block(); | |
e8be2606 FG |
1648 | let or_span = candidate.or_span.take().unwrap(); |
1649 | let source_info = self.source_info(or_span); | |
1650 | if candidate.false_edge_start_block.is_none() { | |
1651 | candidate.false_edge_start_block = | |
1652 | candidate.subcandidates[0].false_edge_start_block; | |
1653 | } | |
74b04a01 XL |
1654 | for subcandidate in mem::take(&mut candidate.subcandidates) { |
1655 | let or_block = subcandidate.pre_binding_block.unwrap(); | |
1656 | self.cfg.goto(or_block, source_info, any_matches); | |
1657 | } | |
1658 | candidate.pre_binding_block = Some(any_matches); | |
9fa01778 | 1659 | } |
92a42be0 SL |
1660 | } |
1661 | ||
c620b35d FG |
1662 | /// Pick a test to run. Which test doesn't matter as long as it is guaranteed to fully match at |
1663 | /// least one match pair. We currently simply pick the test corresponding to the first match | |
1664 | /// pair of the first candidate in the list. | |
92a42be0 | 1665 | /// |
c620b35d FG |
1666 | /// *Note:* taking the first match pair is somewhat arbitrary, and we might do better here by |
1667 | /// choosing more carefully what to test. | |
92a42be0 SL |
1668 | /// |
1669 | /// For example, consider the following possible match-pairs: | |
1670 | /// | |
5869c6ff XL |
1671 | /// 1. `x @ Some(P)` -- we will do a [`Switch`] to decide what variant `x` has |
1672 | /// 2. `x @ 22` -- we will do a [`SwitchInt`] to decide what value `x` has | |
1673 | /// 3. `x @ 3..5` -- we will do a [`Range`] test to decide what range `x` falls in | |
92a42be0 SL |
1674 | /// 4. etc. |
1675 | /// | |
5869c6ff XL |
1676 | /// [`Switch`]: TestKind::Switch |
1677 | /// [`SwitchInt`]: TestKind::SwitchInt | |
1678 | /// [`Range`]: TestKind::Range | |
e8be2606 | 1679 | fn pick_test(&mut self, candidates: &[&mut Candidate<'_, 'tcx>]) -> (Place<'tcx>, Test<'tcx>) { |
c620b35d FG |
1680 | // Extract the match-pair from the highest priority candidate |
1681 | let match_pair = &candidates.first().unwrap().match_pairs[0]; | |
1682 | let test = self.test(match_pair); | |
e8be2606 FG |
1683 | // Unwrap is ok after simplification. |
1684 | let match_place = match_pair.place.unwrap(); | |
c620b35d FG |
1685 | debug!(?test, ?match_pair); |
1686 | ||
1687 | (match_place, test) | |
1688 | } | |
1689 | ||
1690 | /// Given a test, we sort the input candidates into several buckets. If a candidate only matches | |
1691 | /// in one of the branches of `test`, we move it there. If it could match in more than one of | |
1692 | /// the branches of `test`, we stop sorting candidates. | |
5869c6ff | 1693 | /// |
c620b35d FG |
1694 | /// This returns a pair of |
1695 | /// - the candidates that weren't sorted; | |
1696 | /// - for each possible outcome of the test, the candidates that match in that outcome. | |
92a42be0 | 1697 | /// |
c620b35d FG |
1698 | /// Moreover, we transform the branched candidates to reflect the fact that we know which |
1699 | /// outcome of `test` occurred. | |
92a42be0 | 1700 | /// |
c620b35d | 1701 | /// For example: |
041b39d2 XL |
1702 | /// ``` |
1703 | /// # let (x, y, z) = (true, true, true); | |
3157f602 | 1704 | /// match (x, y, z) { |
04454e1e | 1705 | /// (true , _ , true ) => true, // (0) |
c620b35d FG |
1706 | /// (false, false, _ ) => false, // (1) |
1707 | /// (_ , true , _ ) => true, // (2) | |
04454e1e | 1708 | /// (true , _ , false) => false, // (3) |
3157f602 | 1709 | /// } |
04454e1e | 1710 | /// # ; |
3157f602 XL |
1711 | /// ``` |
1712 | /// | |
c620b35d FG |
1713 | /// Assume we are testing on `x`. There are 2 overlapping candidate sets: |
1714 | /// - If the outcome is that `x` is true, candidates 0, 2, and 3 | |
3157f602 XL |
1715 | /// - If the outcome is that `x` is false, candidates 1 and 2 |
1716 | /// | |
c620b35d FG |
1717 | /// Following our algorithm, candidate 0 is sorted into outcome `x == true`, candidate 1 goes |
1718 | /// into outcome `x == false`, and candidate 2 and 3 remain unsorted. | |
1719 | /// | |
1720 | /// The sorted candidates are transformed: | |
1721 | /// - candidate 0 becomes `[z @ true]` since we know that `x` was `true`; | |
1722 | /// - candidate 1 becomes `[y @ false]` since we know that `x` was `false`. | |
1723 | fn sort_candidates<'b, 'c, 'pat>( | |
1724 | &mut self, | |
e8be2606 | 1725 | match_place: Place<'tcx>, |
c620b35d FG |
1726 | test: &Test<'tcx>, |
1727 | mut candidates: &'b mut [&'c mut Candidate<'pat, 'tcx>], | |
1728 | ) -> ( | |
1729 | &'b mut [&'c mut Candidate<'pat, 'tcx>], | |
1730 | FxIndexMap<TestBranch<'tcx>, Vec<&'b mut Candidate<'pat, 'tcx>>>, | |
1731 | ) { | |
1732 | // For each of the possible outcomes, collect vector of candidates that apply if the test | |
1733 | // has that particular outcome. | |
1734 | let mut target_candidates: FxIndexMap<_, Vec<&mut Candidate<'_, '_>>> = Default::default(); | |
1735 | ||
1736 | let total_candidate_count = candidates.len(); | |
1737 | ||
1738 | // Sort the candidates into the appropriate vector in `target_candidates`. Note that at some | |
1739 | // point we may encounter a candidate where the test is not relevant; at that point, we stop | |
1740 | // sorting. | |
1741 | while let Some(candidate) = candidates.first_mut() { | |
1742 | let Some(branch) = | |
e8be2606 | 1743 | self.sort_candidate(match_place, test, candidate, &target_candidates) |
c620b35d FG |
1744 | else { |
1745 | break; | |
1746 | }; | |
1747 | let (candidate, rest) = candidates.split_first_mut().unwrap(); | |
1748 | target_candidates.entry(branch).or_insert_with(Vec::new).push(candidate); | |
1749 | candidates = rest; | |
1750 | } | |
1751 | ||
1752 | // At least the first candidate ought to be tested | |
1753 | assert!( | |
1754 | total_candidate_count > candidates.len(), | |
1755 | "{total_candidate_count}, {candidates:#?}" | |
1756 | ); | |
1757 | debug!("tested_candidates: {}", total_candidate_count - candidates.len()); | |
1758 | debug!("untested_candidates: {}", candidates.len()); | |
1759 | ||
1760 | (candidates, target_candidates) | |
1761 | } | |
1762 | ||
1763 | /// This is the most subtle part of the match lowering algorithm. At this point, the input | |
1764 | /// candidates have been fully simplified, so all remaining match-pairs require some sort of | |
1765 | /// test. | |
1766 | /// | |
1767 | /// Once we pick what sort of test we are going to perform, this test will help us winnow down | |
1768 | /// our candidates. So we walk over the candidates (from high to low priority) and check. We | |
1769 | /// compute, for each outcome of the test, a transformed list of candidates. If a candidate | |
1770 | /// matches in a single branch of our test, we add it to the corresponding outcome. We also | |
1771 | /// transform it to record the fact that we know which outcome occurred. | |
1772 | /// | |
1773 | /// For example, if we are testing `x.0`'s variant, and we have a candidate `(x.0 @ Some(v), x.1 | |
1774 | /// @ 22)`, then we would have a resulting candidate of `((x.0 as Some).0 @ v, x.1 @ 22)` in the | |
1775 | /// branch corresponding to `Some`. To ensure we make progress, we always pick a test that | |
1776 | /// results in simplifying the first candidate. | |
1777 | /// | |
1778 | /// But there may also be candidates that the test doesn't | |
1779 | /// apply to. The classical example is wildcards: | |
1780 | /// | |
1781 | /// ``` | |
1782 | /// # let (x, y, z) = (true, true, true); | |
1783 | /// match (x, y, z) { | |
1784 | /// (true , _ , true ) => true, // (0) | |
1785 | /// (false, false, _ ) => false, // (1) | |
1786 | /// (_ , true , _ ) => true, // (2) | |
1787 | /// (true , _ , false) => false, // (3) | |
1788 | /// } | |
1789 | /// # ; | |
1790 | /// ``` | |
1791 | /// | |
1792 | /// Here, the traditional "decision tree" method would generate 2 separate code-paths for the 2 | |
1793 | /// possible values of `x`. This would however duplicate some candidates, which would need to be | |
1794 | /// lowered several times. | |
3157f602 XL |
1795 | /// |
1796 | /// In some cases, this duplication can create an exponential amount of | |
1797 | /// code. This is most easily seen by noticing that this method terminates | |
1798 | /// with precisely the reachable arms being reachable - but that problem | |
1799 | /// is trivially NP-complete: | |
1800 | /// | |
04454e1e FG |
1801 | /// ```ignore (illustrative) |
1802 | /// match (var0, var1, var2, var3, ...) { | |
1803 | /// (true , _ , _ , false, true, ...) => false, | |
1804 | /// (_ , true, true , false, _ , ...) => false, | |
1805 | /// (false, _ , false, false, _ , ...) => false, | |
1806 | /// ... | |
1807 | /// _ => true | |
1808 | /// } | |
3157f602 XL |
1809 | /// ``` |
1810 | /// | |
1811 | /// Here the last arm is reachable only if there is an assignment to | |
1812 | /// the variables that does not match any of the literals. Therefore, | |
1813 | /// compilation would take an exponential amount of time in some cases. | |
1814 | /// | |
c620b35d FG |
1815 | /// In rustc, we opt instead for the "backtracking automaton" approach. This guarantees we never |
1816 | /// duplicate a candidate (except in the presence of or-patterns). In fact this guarantee is | |
1817 | /// ensured by the fact that we carry around `&mut Candidate`s which can't be duplicated. | |
3157f602 | 1818 | /// |
c620b35d FG |
1819 | /// To make this work, whenever we decide to perform a test, if we encounter a candidate that |
1820 | /// could match in more than one branch of the test, we stop. We generate code for the test and | |
1821 | /// for the candidates in its branches; the remaining candidates will be tested if the | |
1822 | /// candidates in the branches fail to match. | |
1823 | /// | |
1824 | /// For example, if we test on `x` in the following: | |
1825 | /// ``` | |
1826 | /// # fn foo((x, y, z): (bool, bool, bool)) -> u32 { | |
1827 | /// match (x, y, z) { | |
1828 | /// (true , _ , true ) => 0, | |
1829 | /// (false, false, _ ) => 1, | |
1830 | /// (_ , true , _ ) => 2, | |
1831 | /// (true , _ , false) => 3, | |
92a42be0 | 1832 | /// } |
c620b35d FG |
1833 | /// # } |
1834 | /// ``` | |
1835 | /// this function generates code that looks more of less like: | |
1836 | /// ``` | |
1837 | /// # fn foo((x, y, z): (bool, bool, bool)) -> u32 { | |
1838 | /// if x { | |
1839 | /// match (y, z) { | |
1840 | /// (_, true) => return 0, | |
1841 | /// _ => {} // continue matching | |
1842 | /// } | |
1843 | /// } else { | |
1844 | /// match (y, z) { | |
1845 | /// (false, _) => return 1, | |
1846 | /// _ => {} // continue matching | |
1847 | /// } | |
1848 | /// } | |
1849 | /// // the block here is `remainder_start` | |
1850 | /// match (x, y, z) { | |
1851 | /// (_ , true , _ ) => 2, | |
1852 | /// (true , _ , false) => 3, | |
1853 | /// _ => unreachable!(), | |
1854 | /// } | |
1855 | /// # } | |
92a42be0 | 1856 | /// ``` |
9fa01778 | 1857 | fn test_candidates<'pat, 'b, 'c>( |
b7449926 XL |
1858 | &mut self, |
1859 | span: Span, | |
94222f64 | 1860 | scrutinee_span: Span, |
c620b35d FG |
1861 | candidates: &'b mut [&'c mut Candidate<'pat, 'tcx>], |
1862 | start_block: BasicBlock, | |
1863 | otherwise_block: BasicBlock, | |
dc9dc135 | 1864 | ) { |
c620b35d FG |
1865 | // Extract the match-pair from the highest priority candidate and build a test from it. |
1866 | let (match_place, test) = self.pick_test(candidates); | |
92a42be0 | 1867 | |
c620b35d FG |
1868 | // For each of the N possible test outcomes, build the vector of candidates that applies if |
1869 | // the test has that particular outcome. | |
1870 | let (remaining_candidates, target_candidates) = | |
e8be2606 | 1871 | self.sort_candidates(match_place, &test, candidates); |
92a42be0 | 1872 | |
4b012472 | 1873 | // The block that we should branch to if none of the |
c620b35d FG |
1874 | // `target_candidates` match. |
1875 | let remainder_start = if !remaining_candidates.is_empty() { | |
1876 | let remainder_start = self.cfg.start_new_block(); | |
4b012472 FG |
1877 | self.match_candidates( |
1878 | span, | |
1879 | scrutinee_span, | |
1880 | remainder_start, | |
1881 | otherwise_block, | |
c620b35d | 1882 | remaining_candidates, |
4b012472 | 1883 | ); |
c620b35d FG |
1884 | remainder_start |
1885 | } else { | |
1886 | otherwise_block | |
1887 | }; | |
1888 | ||
1889 | // For each outcome of test, process the candidates that still apply. | |
1890 | let target_blocks: FxIndexMap<_, _> = target_candidates | |
1891 | .into_iter() | |
1892 | .map(|(branch, mut candidates)| { | |
1893 | let candidate_start = self.cfg.start_new_block(); | |
1894 | self.match_candidates( | |
1895 | span, | |
1896 | scrutinee_span, | |
1897 | candidate_start, | |
1898 | remainder_start, | |
1899 | &mut *candidates, | |
1900 | ); | |
1901 | (branch, candidate_start) | |
1902 | }) | |
1903 | .collect(); | |
92a42be0 | 1904 | |
c620b35d FG |
1905 | // Perform the test, branching to one of N blocks. |
1906 | self.perform_test( | |
1907 | span, | |
1908 | scrutinee_span, | |
1909 | start_block, | |
1910 | remainder_start, | |
e8be2606 | 1911 | match_place, |
c620b35d FG |
1912 | &test, |
1913 | target_blocks, | |
1914 | ); | |
9fa01778 | 1915 | } |
9fa01778 | 1916 | } |
e9174d1e | 1917 | |
9fa01778 | 1918 | /////////////////////////////////////////////////////////////////////////// |
e74abb32 | 1919 | // Pat binding - used for `let` and function parameters as well. |
9fa01778 | 1920 | |
dc9dc135 | 1921 | impl<'a, 'tcx> Builder<'a, 'tcx> { |
487cf647 FG |
1922 | /// If the bindings have already been declared, set `declare_bindings` to |
1923 | /// `false` to avoid duplicated bindings declaration. Used for if-let guards. | |
923072b8 | 1924 | pub(crate) fn lower_let_expr( |
94222f64 XL |
1925 | &mut self, |
1926 | mut block: BasicBlock, | |
c0240ec0 | 1927 | expr_id: ExprId, |
94222f64 | 1928 | pat: &Pat<'tcx>, |
923072b8 | 1929 | source_scope: Option<SourceScope>, |
94222f64 | 1930 | span: Span, |
487cf647 | 1931 | declare_bindings: bool, |
94222f64 | 1932 | ) -> BlockAnd<()> { |
c0240ec0 FG |
1933 | let expr_span = self.thir[expr_id].span; |
1934 | let expr_place_builder = unpack!(block = self.lower_scrutinee(block, expr_id, expr_span)); | |
94222f64 | 1935 | let wildcard = Pat::wildcard_from_ty(pat.ty); |
4b012472 | 1936 | let mut guard_candidate = Candidate::new(expr_place_builder.clone(), pat, false, self); |
2b03887a FG |
1937 | let mut otherwise_candidate = |
1938 | Candidate::new(expr_place_builder.clone(), &wildcard, false, self); | |
94222f64 XL |
1939 | let fake_borrow_temps = self.lower_match_tree( |
1940 | block, | |
1941 | pat.span, | |
ed00b5ec | 1942 | &expr_place_builder, |
94222f64 XL |
1943 | pat.span, |
1944 | false, | |
1945 | &mut [&mut guard_candidate, &mut otherwise_candidate], | |
1946 | ); | |
487cf647 FG |
1947 | let expr_place = expr_place_builder.try_to_place(self); |
1948 | let opt_expr_place = expr_place.as_ref().map(|place| (Some(place), expr_span)); | |
94222f64 | 1949 | let otherwise_post_guard_block = otherwise_candidate.pre_binding_block.unwrap(); |
c620b35d | 1950 | self.break_for_else(otherwise_post_guard_block, self.source_info(expr_span)); |
94222f64 | 1951 | |
487cf647 FG |
1952 | if declare_bindings { |
1953 | self.declare_bindings(source_scope, pat.span.to(span), pat, None, opt_expr_place); | |
1954 | } | |
923072b8 | 1955 | |
94222f64 XL |
1956 | let post_guard_block = self.bind_pattern( |
1957 | self.source_info(pat.span), | |
1958 | guard_candidate, | |
c620b35d | 1959 | fake_borrow_temps.as_slice(), |
c0240ec0 | 1960 | expr_span, |
94222f64 | 1961 | None, |
f2b60f7d | 1962 | false, |
94222f64 XL |
1963 | ); |
1964 | ||
1965 | post_guard_block.unit() | |
1966 | } | |
1967 | ||
e9174d1e | 1968 | /// Initializes each of the bindings from the candidate by |
9fa01778 XL |
1969 | /// moving/copying/ref'ing the source as appropriate. Tests the guard, if |
1970 | /// any, and then branches to the arm. Returns the block for the case where | |
fc512014 | 1971 | /// the guard succeeds. |
e9174d1e | 1972 | /// |
e1599b0c XL |
1973 | /// Note: we do not check earlier that if there is a guard, |
1974 | /// there cannot be move bindings. We avoid a use-after-move by only | |
1975 | /// moving the binding once the guard has evaluated to true (see below). | |
b7449926 XL |
1976 | fn bind_and_guard_matched_candidate<'pat>( |
1977 | &mut self, | |
b7449926 | 1978 | candidate: Candidate<'pat, 'tcx>, |
c620b35d | 1979 | parent_data: &[PatternExtraData<'tcx>], |
e8be2606 | 1980 | fake_borrows: &[(Place<'tcx>, Local, FakeBorrowKind)], |
9fa01778 | 1981 | scrutinee_span: Span, |
487cf647 | 1982 | arm_match_scope: Option<(&Arm<'tcx>, region::Scope)>, |
74b04a01 | 1983 | schedule_drops: bool, |
f2b60f7d | 1984 | storages_alive: bool, |
dc9dc135 | 1985 | ) -> BasicBlock { |
9fa01778 | 1986 | debug!("bind_and_guard_matched_candidate(candidate={:?})", candidate); |
e9174d1e SL |
1987 | |
1988 | debug_assert!(candidate.match_pairs.is_empty()); | |
1989 | ||
c620b35d | 1990 | let candidate_source_info = self.source_info(candidate.extra_data.span); |
abe05a73 | 1991 | |
74b04a01 | 1992 | let mut block = candidate.pre_binding_block.unwrap(); |
dc9dc135 | 1993 | |
e8be2606 | 1994 | if candidate.next_candidate_start_block.is_some() { |
dc9dc135 XL |
1995 | let fresh_block = self.cfg.start_new_block(); |
1996 | self.false_edges( | |
1997 | block, | |
1998 | fresh_block, | |
e8be2606 | 1999 | candidate.next_candidate_start_block, |
dc9dc135 XL |
2000 | candidate_source_info, |
2001 | ); | |
2002 | block = fresh_block; | |
dc9dc135 | 2003 | } |
e9174d1e | 2004 | |
74b04a01 XL |
2005 | self.ascribe_types( |
2006 | block, | |
c620b35d | 2007 | parent_data |
74b04a01 | 2008 | .iter() |
c620b35d | 2009 | .flat_map(|d| &d.ascriptions) |
923072b8 | 2010 | .cloned() |
c620b35d | 2011 | .chain(candidate.extra_data.ascriptions), |
74b04a01 XL |
2012 | ); |
2013 | ||
83c7162d XL |
2014 | // rust-lang/rust#27282: The `autoref` business deserves some |
2015 | // explanation here. | |
2016 | // | |
2017 | // The intent of the `autoref` flag is that when it is true, | |
2018 | // then any pattern bindings of type T will map to a `&T` | |
2019 | // within the context of the guard expression, but will | |
2020 | // continue to map to a `T` in the context of the arm body. To | |
2021 | // avoid surfacing this distinction in the user source code | |
2022 | // (which would be a severe change to the language and require | |
2023 | // far more revision to the compiler), when `autoref` is true, | |
2024 | // then any occurrence of the identifier in the guard | |
2025 | // expression will automatically get a deref op applied to it. | |
2026 | // | |
2027 | // So an input like: | |
2028 | // | |
2029 | // ``` | |
2030 | // let place = Foo::new(); | |
2031 | // match place { foo if inspect(foo) | |
9c376795 | 2032 | // => feed(foo), ... } |
83c7162d XL |
2033 | // ``` |
2034 | // | |
2035 | // will be treated as if it were really something like: | |
2036 | // | |
2037 | // ``` | |
2038 | // let place = Foo::new(); | |
2039 | // match place { Foo { .. } if { let tmp1 = &place; inspect(*tmp1) } | |
2040 | // => { let tmp2 = place; feed(tmp2) }, ... } | |
353b0b11 | 2041 | // ``` |
83c7162d XL |
2042 | // |
2043 | // And an input like: | |
2044 | // | |
2045 | // ``` | |
2046 | // let place = Foo::new(); | |
2047 | // match place { ref mut foo if inspect(foo) | |
9c376795 | 2048 | // => feed(foo), ... } |
83c7162d XL |
2049 | // ``` |
2050 | // | |
2051 | // will be treated as if it were really something like: | |
2052 | // | |
2053 | // ``` | |
2054 | // let place = Foo::new(); | |
2055 | // match place { Foo { .. } if { let tmp1 = & &mut place; inspect(*tmp1) } | |
2056 | // => { let tmp2 = &mut place; feed(tmp2) }, ... } | |
2057 | // ``` | |
2058 | // | |
2059 | // In short, any pattern binding will always look like *some* | |
2060 | // kind of `&T` within the guard at least in terms of how the | |
2061 | // MIR-borrowck views it, and this will ensure that guard | |
2062 | // expressions cannot mutate their the match inputs via such | |
2063 | // bindings. (It also ensures that guard expressions can at | |
2064 | // most *copy* values from such bindings; non-Copy things | |
2065 | // cannot be moved via pattern bindings in guard expressions.) | |
2066 | // | |
2067 | // ---- | |
2068 | // | |
2069 | // Implementation notes (under assumption `autoref` is true). | |
2070 | // | |
2071 | // To encode the distinction above, we must inject the | |
2072 | // temporaries `tmp1` and `tmp2`. | |
2073 | // | |
2074 | // There are two cases of interest: binding by-value, and binding by-ref. | |
2075 | // | |
2076 | // 1. Binding by-value: Things are simple. | |
2077 | // | |
2078 | // * Establishing `tmp1` creates a reference into the | |
2079 | // matched place. This code is emitted by | |
2080 | // bind_matched_candidate_for_guard. | |
2081 | // | |
2082 | // * `tmp2` is only initialized "lazily", after we have | |
2083 | // checked the guard. Thus, the code that can trigger | |
2084 | // moves out of the candidate can only fire after the | |
2085 | // guard evaluated to true. This initialization code is | |
2086 | // emitted by bind_matched_candidate_for_arm. | |
2087 | // | |
2088 | // 2. Binding by-reference: Things are tricky. | |
2089 | // | |
2090 | // * Here, the guard expression wants a `&&` or `&&mut` | |
2091 | // into the original input. This means we need to borrow | |
9fa01778 XL |
2092 | // the reference that we create for the arm. |
2093 | // * So we eagerly create the reference for the arm and then take a | |
2094 | // reference to that. | |
487cf647 | 2095 | if let Some((arm, match_scope)) = arm_match_scope |
c0240ec0 | 2096 | && let Some(guard) = arm.guard |
487cf647 | 2097 | { |
6a06907d | 2098 | let tcx = self.tcx; |
c620b35d FG |
2099 | let bindings = |
2100 | parent_data.iter().flat_map(|d| &d.bindings).chain(&candidate.extra_data.bindings); | |
48663c56 | 2101 | |
74b04a01 | 2102 | self.bind_matched_candidate_for_guard(block, schedule_drops, bindings.clone()); |
e8be2606 FG |
2103 | let guard_frame = |
2104 | GuardFrame { locals: bindings.map(|b| GuardFrameLocal::new(b.var_id)).collect() }; | |
416331ca | 2105 | debug!("entering guard building context: {:?}", guard_frame); |
48663c56 | 2106 | self.guard_context.push(guard_frame); |
83c7162d | 2107 | |
48663c56 | 2108 | let re_erased = tcx.lifetimes.re_erased; |
9fa01778 | 2109 | let scrutinee_source_info = self.source_info(scrutinee_span); |
e8be2606 FG |
2110 | for &(place, temp, kind) in fake_borrows { |
2111 | let borrow = Rvalue::Ref(re_erased, BorrowKind::Fake(kind), place); | |
ba9703b0 | 2112 | self.cfg.push_assign(block, scrutinee_source_info, Place::from(temp), borrow); |
9fa01778 XL |
2113 | } |
2114 | ||
94222f64 XL |
2115 | let mut guard_span = rustc_span::DUMMY_SP; |
2116 | ||
2117 | let (post_guard_block, otherwise_post_guard_block) = | |
c0240ec0 FG |
2118 | self.in_if_then_scope(match_scope, guard_span, |this| { |
2119 | guard_span = this.thir[guard].span; | |
2120 | this.then_else_break( | |
2121 | block, | |
2122 | guard, | |
c620b35d | 2123 | None, // Use `self.local_scope()` as the temp scope |
c0240ec0 | 2124 | this.source_info(arm.span), |
c620b35d | 2125 | false, // For guards, `let` bindings are declared separately |
c0240ec0 | 2126 | ) |
94222f64 XL |
2127 | }); |
2128 | ||
fc512014 XL |
2129 | let source_info = self.source_info(guard_span); |
2130 | let guard_end = self.source_info(tcx.sess.source_map().end_point(guard_span)); | |
48663c56 | 2131 | let guard_frame = self.guard_context.pop().unwrap(); |
dfeec247 | 2132 | debug!("Exiting guard building context with locals: {:?}", guard_frame); |
abe05a73 | 2133 | |
e8be2606 | 2134 | for &(_, temp, _) in fake_borrows { |
60c5eb7d XL |
2135 | let cause = FakeReadCause::ForMatchGuard; |
2136 | self.cfg.push_fake_read(post_guard_block, guard_end, cause, Place::from(temp)); | |
9fa01778 | 2137 | } |
94b46f34 | 2138 | |
74b04a01 XL |
2139 | let otherwise_block = candidate.otherwise_block.unwrap_or_else(|| { |
2140 | let unreachable = self.cfg.start_new_block(); | |
2141 | self.cfg.terminate(unreachable, source_info, TerminatorKind::Unreachable); | |
2142 | unreachable | |
2143 | }); | |
74b04a01 | 2144 | self.false_edges( |
94222f64 | 2145 | otherwise_post_guard_block, |
74b04a01 | 2146 | otherwise_block, |
e8be2606 | 2147 | candidate.next_candidate_start_block, |
74b04a01 | 2148 | source_info, |
dc9dc135 XL |
2149 | ); |
2150 | ||
94b46f34 XL |
2151 | // We want to ensure that the matched candidates are bound |
2152 | // after we have confirmed this candidate *and* any | |
2153 | // associated guard; Binding them on `block` is too soon, | |
2154 | // because that would be before we've checked the result | |
2155 | // from the guard. | |
2156 | // | |
dc9dc135 | 2157 | // But binding them on the arm is *too late*, because |
94b46f34 XL |
2158 | // then all of the candidates for a single arm would be |
2159 | // bound in the same place, that would cause a case like: | |
2160 | // | |
2161 | // ```rust | |
2162 | // match (30, 2) { | |
2163 | // (mut x, 1) | (2, mut x) if { true } => { ... } | |
2164 | // ... // ^^^^^^^ (this is `arm_block`) | |
2165 | // } | |
2166 | // ``` | |
2167 | // | |
94222f64 | 2168 | // would yield an `arm_block` something like: |
94b46f34 XL |
2169 | // |
2170 | // ``` | |
2171 | // StorageLive(_4); // _4 is `x` | |
2172 | // _4 = &mut (_1.0: i32); // this is handling `(mut x, 1)` case | |
2173 | // _4 = &mut (_1.1: i32); // this is handling `(2, mut x)` case | |
2174 | // ``` | |
2175 | // | |
2176 | // and that is clearly not correct. | |
c620b35d | 2177 | let by_value_bindings = parent_data |
fc512014 | 2178 | .iter() |
c620b35d FG |
2179 | .flat_map(|d| &d.bindings) |
2180 | .chain(&candidate.extra_data.bindings) | |
e8be2606 | 2181 | .filter(|binding| matches!(binding.binding_mode.0, ByRef::No)); |
48663c56 XL |
2182 | // Read all of the by reference bindings to ensure that the |
2183 | // place they refer to can't be modified by the guard. | |
2184 | for binding in by_value_bindings.clone() { | |
2185 | let local_id = self.var_local_id(binding.var_id, RefWithinGuard); | |
60c5eb7d XL |
2186 | let cause = FakeReadCause::ForGuardBinding; |
2187 | self.cfg.push_fake_read(post_guard_block, guard_end, cause, Place::from(local_id)); | |
83c7162d | 2188 | } |
74b04a01 | 2189 | assert!(schedule_drops, "patterns with guards must schedule drops"); |
f2b60f7d FG |
2190 | self.bind_matched_candidate_for_arm_body( |
2191 | post_guard_block, | |
2192 | true, | |
2193 | by_value_bindings, | |
2194 | storages_alive, | |
2195 | ); | |
94b46f34 | 2196 | |
dc9dc135 | 2197 | post_guard_block |
e9174d1e | 2198 | } else { |
94b46f34 XL |
2199 | // (Here, it is not too early to bind the matched |
2200 | // candidate on `block`, because there is no guard result | |
2201 | // that we have to inspect before we bind them.) | |
74b04a01 XL |
2202 | self.bind_matched_candidate_for_arm_body( |
2203 | block, | |
2204 | schedule_drops, | |
c620b35d | 2205 | parent_data.iter().flat_map(|d| &d.bindings).chain(&candidate.extra_data.bindings), |
f2b60f7d | 2206 | storages_alive, |
74b04a01 | 2207 | ); |
dc9dc135 | 2208 | block |
e9174d1e SL |
2209 | } |
2210 | } | |
2211 | ||
b7449926 XL |
2212 | /// Append `AscribeUserType` statements onto the end of `block` |
2213 | /// for each ascription | |
923072b8 | 2214 | fn ascribe_types( |
74b04a01 XL |
2215 | &mut self, |
2216 | block: BasicBlock, | |
923072b8 FG |
2217 | ascriptions: impl IntoIterator<Item = Ascription<'tcx>>, |
2218 | ) { | |
b7449926 | 2219 | for ascription in ascriptions { |
923072b8 | 2220 | let source_info = self.source_info(ascription.annotation.span); |
0bf4aa26 | 2221 | |
923072b8 | 2222 | let base = self.canonical_user_type_annotations.push(ascription.annotation); |
b7449926 XL |
2223 | self.cfg.push( |
2224 | block, | |
2225 | Statement { | |
2226 | source_info, | |
2227 | kind: StatementKind::AscribeUserType( | |
923072b8 FG |
2228 | Box::new(( |
2229 | ascription.source, | |
2230 | UserTypeProjection { base, projs: Vec::new() }, | |
2231 | )), | |
0731742a | 2232 | ascription.variance, |
b7449926 XL |
2233 | ), |
2234 | }, | |
2235 | ); | |
2236 | } | |
2237 | } | |
2238 | ||
74b04a01 XL |
2239 | fn bind_matched_candidate_for_guard<'b>( |
2240 | &mut self, | |
2241 | block: BasicBlock, | |
2242 | schedule_drops: bool, | |
2243 | bindings: impl IntoIterator<Item = &'b Binding<'tcx>>, | |
2244 | ) where | |
2245 | 'tcx: 'b, | |
2246 | { | |
2247 | debug!("bind_matched_candidate_for_guard(block={:?})", block); | |
e9174d1e | 2248 | |
83c7162d XL |
2249 | // Assign each of the bindings. Since we are binding for a |
2250 | // guard expression, this will never trigger moves out of the | |
2251 | // candidate. | |
6a06907d | 2252 | let re_erased = self.tcx.lifetimes.re_erased; |
83c7162d | 2253 | for binding in bindings { |
74b04a01 | 2254 | debug!("bind_matched_candidate_for_guard(binding={:?})", binding); |
83c7162d | 2255 | let source_info = self.source_info(binding.span); |
94b46f34 XL |
2256 | |
2257 | // For each pattern ident P of type T, `ref_for_guard` is | |
2258 | // a reference R: &T pointing to the location matched by | |
2259 | // the pattern, and every occurrence of P within a guard | |
2260 | // denotes *R. | |
74b04a01 XL |
2261 | let ref_for_guard = self.storage_live_binding( |
2262 | block, | |
2263 | binding.var_id, | |
2264 | binding.span, | |
2265 | RefWithinGuard, | |
2266 | schedule_drops, | |
2267 | ); | |
e8be2606 FG |
2268 | match binding.binding_mode.0 { |
2269 | ByRef::No => { | |
dfeec247 | 2270 | let rvalue = Rvalue::Ref(re_erased, BorrowKind::Shared, binding.source); |
ba9703b0 | 2271 | self.cfg.push_assign(block, source_info, ref_for_guard, rvalue); |
83c7162d | 2272 | } |
e8be2606 | 2273 | ByRef::Yes(mutbl) => { |
9fa01778 | 2274 | let value_for_arm = self.storage_live_binding( |
b7449926 XL |
2275 | block, |
2276 | binding.var_id, | |
2277 | binding.span, | |
9fa01778 | 2278 | OutsideGuard, |
74b04a01 | 2279 | schedule_drops, |
b7449926 | 2280 | ); |
94b46f34 | 2281 | |
e8be2606 FG |
2282 | let rvalue = |
2283 | Rvalue::Ref(re_erased, util::ref_pat_borrow_kind(mutbl), binding.source); | |
ba9703b0 | 2284 | self.cfg.push_assign(block, source_info, value_for_arm, rvalue); |
9fa01778 | 2285 | let rvalue = Rvalue::Ref(re_erased, BorrowKind::Shared, value_for_arm); |
ba9703b0 | 2286 | self.cfg.push_assign(block, source_info, ref_for_guard, rvalue); |
83c7162d XL |
2287 | } |
2288 | } | |
2289 | } | |
2290 | } | |
2291 | ||
9fa01778 | 2292 | fn bind_matched_candidate_for_arm_body<'b>( |
b7449926 XL |
2293 | &mut self, |
2294 | block: BasicBlock, | |
74b04a01 | 2295 | schedule_drops: bool, |
9fa01778 | 2296 | bindings: impl IntoIterator<Item = &'b Binding<'tcx>>, |
f2b60f7d | 2297 | storages_alive: bool, |
dfeec247 XL |
2298 | ) where |
2299 | 'tcx: 'b, | |
2300 | { | |
9fa01778 | 2301 | debug!("bind_matched_candidate_for_arm_body(block={:?})", block); |
0731742a | 2302 | |
6a06907d | 2303 | let re_erased = self.tcx.lifetimes.re_erased; |
e9174d1e SL |
2304 | // Assign each of the bindings. This may trigger moves out of the candidate. |
2305 | for binding in bindings { | |
8bb4bdeb | 2306 | let source_info = self.source_info(binding.span); |
f2b60f7d FG |
2307 | let local = if storages_alive { |
2308 | // Here storages are already alive, probably because this is a binding | |
2309 | // from let-else. | |
2310 | // We just need to schedule drop for the value. | |
2311 | self.var_local_id(binding.var_id, OutsideGuard).into() | |
2312 | } else { | |
2313 | self.storage_live_binding( | |
2314 | block, | |
2315 | binding.var_id, | |
2316 | binding.span, | |
2317 | OutsideGuard, | |
2318 | schedule_drops, | |
2319 | ) | |
2320 | }; | |
74b04a01 XL |
2321 | if schedule_drops { |
2322 | self.schedule_drop_for_binding(binding.var_id, binding.span, OutsideGuard); | |
2323 | } | |
e8be2606 FG |
2324 | let rvalue = match binding.binding_mode.0 { |
2325 | ByRef::No => Rvalue::Use(self.consume_by_copy_or_move(binding.source)), | |
2326 | ByRef::Yes(mutbl) => { | |
2327 | Rvalue::Ref(re_erased, util::ref_pat_borrow_kind(mutbl), binding.source) | |
83c7162d | 2328 | } |
e9174d1e | 2329 | }; |
ba9703b0 | 2330 | self.cfg.push_assign(block, source_info, local, rvalue); |
e9174d1e SL |
2331 | } |
2332 | } | |
2333 | ||
9fa01778 XL |
2334 | /// Each binding (`ref mut var`/`ref var`/`mut var`/`var`, where the bound |
2335 | /// `var` has type `T` in the arm body) in a pattern maps to 2 locals. The | |
2336 | /// first local is a binding for occurrences of `var` in the guard, which | |
2337 | /// will have type `&T`. The second local is a binding for occurrences of | |
2338 | /// `var` in the arm body, which will have type `T`. | |
2b03887a | 2339 | #[instrument(skip(self), level = "debug")] |
b7449926 XL |
2340 | fn declare_binding( |
2341 | &mut self, | |
2342 | source_info: SourceInfo, | |
2343 | visibility_scope: SourceScope, | |
f9f354fc | 2344 | name: Symbol, |
b7449926 | 2345 | mode: BindingMode, |
923072b8 | 2346 | var_id: LocalVarId, |
b7449926 | 2347 | var_ty: Ty<'tcx>, |
532ac7d7 | 2348 | user_ty: UserTypeProjections, |
b7449926 XL |
2349 | has_guard: ArmHasGuard, |
2350 | opt_match_place: Option<(Option<Place<'tcx>>, Span)>, | |
2351 | pat_span: Span, | |
2352 | ) { | |
6a06907d | 2353 | let tcx = self.tcx; |
dfeec247 | 2354 | let debug_source_info = SourceInfo { span: source_info.span, scope: visibility_scope }; |
9c376795 | 2355 | let local = LocalDecl { |
e8be2606 | 2356 | mutability: mode.1, |
b7449926 | 2357 | ty: var_ty, |
94222f64 | 2358 | user_ty: if user_ty.is_empty() { None } else { Some(Box::new(user_ty)) }, |
3b2f2976 | 2359 | source_info, |
353b0b11 | 2360 | local_info: ClearCrossCrate::Set(Box::new(LocalInfo::User(BindingForm::Var( |
3dfed10e | 2361 | VarBindingForm { |
e8be2606 | 2362 | binding_mode: mode, |
3dfed10e XL |
2363 | // hypothetically, `visit_primary_bindings` could try to unzip |
2364 | // an outermost hir::Ty as we descend, matching up | |
2365 | // idents in pat; but complex w/ unclear UI payoff. | |
2366 | // Instead, just abandon providing diagnostic info. | |
2367 | opt_ty_info: None, | |
2368 | opt_match_place, | |
2369 | pat_span, | |
2370 | }, | |
353b0b11 | 2371 | )))), |
94b46f34 | 2372 | }; |
dc9dc135 | 2373 | let for_arm_body = self.local_decls.push(local); |
60c5eb7d XL |
2374 | self.var_debug_info.push(VarDebugInfo { |
2375 | name, | |
2376 | source_info: debug_source_info, | |
fc512014 | 2377 | value: VarDebugInfoContents::Place(for_arm_body.into()), |
781aab86 | 2378 | composite: None, |
353b0b11 | 2379 | argument_index: None, |
60c5eb7d | 2380 | }); |
48663c56 | 2381 | let locals = if has_guard.0 { |
94b46f34 | 2382 | let ref_for_guard = self.local_decls.push(LocalDecl::<'tcx> { |
9fa01778 XL |
2383 | // This variable isn't mutated but has a name, so has to be |
2384 | // immutable to avoid the unused mut lint. | |
b7449926 | 2385 | mutability: Mutability::Not, |
fe692bf9 | 2386 | ty: Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, var_ty), |
f9f354fc | 2387 | user_ty: None, |
83c7162d | 2388 | source_info, |
353b0b11 | 2389 | local_info: ClearCrossCrate::Set(Box::new(LocalInfo::User( |
3dfed10e | 2390 | BindingForm::RefForGuard, |
353b0b11 | 2391 | ))), |
60c5eb7d XL |
2392 | }); |
2393 | self.var_debug_info.push(VarDebugInfo { | |
2394 | name, | |
2395 | source_info: debug_source_info, | |
fc512014 | 2396 | value: VarDebugInfoContents::Place(ref_for_guard.into()), |
781aab86 | 2397 | composite: None, |
353b0b11 | 2398 | argument_index: None, |
83c7162d | 2399 | }); |
dfeec247 | 2400 | LocalsForNode::ForGuard { ref_for_guard, for_arm_body } |
83c7162d XL |
2401 | } else { |
2402 | LocalsForNode::One(for_arm_body) | |
2403 | }; | |
2b03887a | 2404 | debug!(?locals); |
83c7162d | 2405 | self.var_indices.insert(var_id, locals); |
e9174d1e | 2406 | } |
064997fb FG |
2407 | |
2408 | pub(crate) fn ast_let_else( | |
2409 | &mut self, | |
2410 | mut block: BasicBlock, | |
c0240ec0 | 2411 | init_id: ExprId, |
064997fb | 2412 | initializer_span: Span, |
f2b60f7d FG |
2413 | else_block: BlockId, |
2414 | let_else_scope: ®ion::Scope, | |
064997fb | 2415 | pattern: &Pat<'tcx>, |
f2b60f7d FG |
2416 | ) -> BlockAnd<BasicBlock> { |
2417 | let else_block_span = self.thir[else_block].span; | |
2418 | let (matching, failure) = self.in_if_then_scope(*let_else_scope, else_block_span, |this| { | |
c0240ec0 FG |
2419 | let scrutinee = unpack!(block = this.lower_scrutinee(block, init_id, initializer_span)); |
2420 | let pat = Pat { ty: pattern.ty, span: else_block_span, kind: PatKind::Wild }; | |
2b03887a FG |
2421 | let mut wildcard = Candidate::new(scrutinee.clone(), &pat, false, this); |
2422 | let mut candidate = Candidate::new(scrutinee.clone(), pattern, false, this); | |
064997fb FG |
2423 | let fake_borrow_temps = this.lower_match_tree( |
2424 | block, | |
2425 | initializer_span, | |
ed00b5ec | 2426 | &scrutinee, |
064997fb FG |
2427 | pattern.span, |
2428 | false, | |
2429 | &mut [&mut candidate, &mut wildcard], | |
2430 | ); | |
2431 | // This block is for the matching case | |
2432 | let matching = this.bind_pattern( | |
2433 | this.source_info(pattern.span), | |
2434 | candidate, | |
c620b35d | 2435 | fake_borrow_temps.as_slice(), |
064997fb FG |
2436 | initializer_span, |
2437 | None, | |
f2b60f7d | 2438 | true, |
064997fb FG |
2439 | ); |
2440 | // This block is for the failure case | |
2441 | let failure = this.bind_pattern( | |
f2b60f7d | 2442 | this.source_info(else_block_span), |
064997fb | 2443 | wildcard, |
c620b35d | 2444 | fake_borrow_temps.as_slice(), |
064997fb FG |
2445 | initializer_span, |
2446 | None, | |
f2b60f7d | 2447 | true, |
064997fb | 2448 | ); |
c620b35d | 2449 | this.break_for_else(failure, this.source_info(initializer_span)); |
064997fb FG |
2450 | matching.unit() |
2451 | }); | |
f2b60f7d | 2452 | matching.and(failure) |
064997fb | 2453 | } |
e9174d1e | 2454 | } |