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