@@ -308,36 +308,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
308
308
unpack ! ( block = self . lower_scrutinee( block, scrutinee_id, scrutinee_span) ) ;
309
309
310
310
let arms = arms. iter ( ) . map ( |arm| & self . thir [ * arm] ) ;
311
- // Assemble the initial list of candidates. These top-level candidates are 1:1 with the
312
- // original match arms, but other parts of match lowering also introduce subcandidates (for
313
- // sub-or-patterns). So inside the algorithm, the candidates list may not correspond to
314
- // match arms directly.
315
- let candidates: Vec < _ > = arms
311
+ let match_start_span = span. shrink_to_lo ( ) . to ( scrutinee_span) ;
312
+ let patterns = arms
316
313
. clone ( )
317
314
. map ( |arm| {
318
- let arm_has_guard = arm. guard . is_some ( ) ;
319
- let arm_candidate =
320
- Candidate :: new ( scrutinee_place. clone ( ) , & arm. pattern , arm_has_guard, self ) ;
321
- arm_candidate
315
+ let has_match_guard =
316
+ if arm. guard . is_some ( ) { HasMatchGuard :: Yes } else { HasMatchGuard :: No } ;
317
+ ( & * arm. pattern , has_match_guard)
322
318
} )
323
319
. collect ( ) ;
324
-
325
- // The set of places that we are creating fake borrows of. If there are no match guards then
326
- // we don't need any fake borrows, so don't track them.
327
- let match_has_guard = candidates. iter ( ) . any ( |candidate| candidate. has_guard ) ;
328
- let fake_borrow_temps: Vec < ( Place < ' tcx > , Local , FakeBorrowKind ) > = if match_has_guard {
329
- util:: collect_fake_borrows ( self , & candidates, scrutinee_span, scrutinee_place. base ( ) )
330
- } else {
331
- Vec :: new ( )
332
- } ;
333
-
334
- let match_start_span = span. shrink_to_lo ( ) . to ( scrutinee_span) ;
335
320
let built_tree = self . lower_match_tree (
336
321
block,
337
322
scrutinee_span,
338
323
& scrutinee_place,
339
324
match_start_span,
340
- candidates ,
325
+ patterns ,
341
326
false ,
342
327
) ;
343
328
@@ -346,9 +331,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
346
331
scrutinee_place,
347
332
scrutinee_span,
348
333
arms,
349
- built_tree. branches ,
334
+ built_tree,
350
335
self . source_info ( span) ,
351
- fake_borrow_temps,
352
336
)
353
337
}
354
338
@@ -380,16 +364,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
380
364
scrutinee_place_builder : PlaceBuilder < ' tcx > ,
381
365
scrutinee_span : Span ,
382
366
arms : impl IntoIterator < Item = & ' pat Arm < ' tcx > > ,
383
- lowered_branches : impl IntoIterator < Item = MatchTreeBranch < ' tcx > > ,
367
+ built_match_tree : BuiltMatchTree < ' tcx > ,
384
368
outer_source_info : SourceInfo ,
385
- fake_borrow_temps : Vec < ( Place < ' tcx > , Local , FakeBorrowKind ) > ,
386
369
) -> BlockAnd < ( ) >
387
370
where
388
371
' tcx : ' pat ,
389
372
{
390
373
let arm_end_blocks: Vec < _ > = arms
391
374
. into_iter ( )
392
- . zip ( lowered_branches )
375
+ . zip ( built_match_tree . branches )
393
376
. map ( |( arm, branch) | {
394
377
debug ! ( "lowering arm {:?}\n corresponding branch = {:?}" , arm, branch) ;
395
378
@@ -425,7 +408,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
425
408
let arm_block = this. bind_pattern (
426
409
outer_source_info,
427
410
branch,
428
- & fake_borrow_temps,
411
+ & built_match_tree . fake_borrow_temps ,
429
412
scrutinee_span,
430
413
Some ( ( arm, match_scope) ) ,
431
414
false ,
@@ -629,13 +612,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
629
612
initializer : PlaceBuilder < ' tcx > ,
630
613
set_match_place : bool ,
631
614
) -> BlockAnd < ( ) > {
632
- let candidate = Candidate :: new ( initializer. clone ( ) , irrefutable_pat, false , self ) ;
633
615
let built_tree = self . lower_match_tree (
634
616
block,
635
617
irrefutable_pat. span ,
636
618
& initializer,
637
619
irrefutable_pat. span ,
638
- vec ! [ candidate ] ,
620
+ vec ! [ ( irrefutable_pat , HasMatchGuard :: No ) ] ,
639
621
false ,
640
622
) ;
641
623
let [ branch] = built_tree. branches . try_into ( ) . unwrap ( ) ;
@@ -1009,12 +991,15 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
1009
991
fn new (
1010
992
place : PlaceBuilder < ' tcx > ,
1011
993
pattern : & ' pat Pat < ' tcx > ,
1012
- has_guard : bool ,
994
+ has_guard : HasMatchGuard ,
1013
995
cx : & mut Builder < ' _ , ' tcx > ,
1014
996
) -> Self {
1015
997
// Use `FlatPat` to build simplified match pairs, then immediately
1016
998
// incorporate them into a new candidate.
1017
- Self :: from_flat_pat ( FlatPat :: new ( place, pattern, cx) , has_guard)
999
+ Self :: from_flat_pat (
1000
+ FlatPat :: new ( place, pattern, cx) ,
1001
+ matches ! ( has_guard, HasMatchGuard :: Yes ) ,
1002
+ )
1018
1003
}
1019
1004
1020
1005
/// Incorporates an already-simplified [`FlatPat`] into a new candidate.
@@ -1254,6 +1239,10 @@ struct MatchTreeBranch<'tcx> {
1254
1239
struct BuiltMatchTree < ' tcx > {
1255
1240
branches : Vec < MatchTreeBranch < ' tcx > > ,
1256
1241
otherwise_block : BasicBlock ,
1242
+ /// If any of the branches had a guard, we collect here the places and locals to fakely borrow
1243
+ /// to ensure match guards can't modify the values as we match them. For more details, see
1244
+ /// [`util::collect_fake_borrows`].
1245
+ fake_borrow_temps : Vec < ( Place < ' tcx > , Local , FakeBorrowKind ) > ,
1257
1246
}
1258
1247
1259
1248
impl < ' tcx > MatchTreeSubBranch < ' tcx > {
@@ -1304,12 +1293,18 @@ impl<'tcx> MatchTreeBranch<'tcx> {
1304
1293
}
1305
1294
}
1306
1295
1296
+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
1297
+ enum HasMatchGuard {
1298
+ Yes ,
1299
+ No ,
1300
+ }
1301
+
1307
1302
impl < ' a , ' tcx > Builder < ' a , ' tcx > {
1308
1303
/// The entrypoint of the matching algorithm. Create the decision tree for the match expression,
1309
1304
/// starting from `block`.
1310
1305
///
1311
- /// Modifies `candidates` to store the bindings and type ascriptions for
1312
- /// that candidate .
1306
+ /// `patterns` is a list of patterns, one for each arm. The associated boolean indicates whether
1307
+ /// the arm has a guard .
1313
1308
///
1314
1309
/// `refutable` indicates whether the candidate list is refutable (for `if let` and `let else`)
1315
1310
/// or not (for `let` and `match`). In the refutable case we return the block to which we branch
@@ -1320,9 +1315,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1320
1315
scrutinee_span : Span ,
1321
1316
scrutinee_place_builder : & PlaceBuilder < ' tcx > ,
1322
1317
match_start_span : Span ,
1323
- mut candidates : Vec < Candidate < ' pat , ' tcx > > ,
1318
+ patterns : Vec < ( & ' pat Pat < ' tcx > , HasMatchGuard ) > ,
1324
1319
refutable : bool ,
1325
- ) -> BuiltMatchTree < ' tcx > {
1320
+ ) -> BuiltMatchTree < ' tcx >
1321
+ where
1322
+ ' tcx : ' pat ,
1323
+ {
1324
+ // Assemble the initial list of candidates. These top-level candidates are 1:1 with the
1325
+ // input patterns, but other parts of match lowering also introduce subcandidates (for
1326
+ // sub-or-patterns). So inside the algorithm, the candidates list may not correspond to
1327
+ // match arms directly.
1328
+ let mut candidates: Vec < _ > = patterns
1329
+ . into_iter ( )
1330
+ . map ( |( pat, has_guard) | {
1331
+ Candidate :: new ( scrutinee_place_builder. clone ( ) , pat, has_guard, self )
1332
+ } )
1333
+ . collect ( ) ;
1334
+
1335
+ let fake_borrow_temps = util:: collect_fake_borrows (
1336
+ self ,
1337
+ & candidates,
1338
+ scrutinee_span,
1339
+ scrutinee_place_builder. base ( ) ,
1340
+ ) ;
1341
+
1326
1342
// See the doc comment on `match_candidates` for why we have an otherwise block.
1327
1343
let otherwise_block = self . cfg . start_new_block ( ) ;
1328
1344
@@ -1408,6 +1424,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1408
1424
BuiltMatchTree {
1409
1425
branches : candidates. into_iter ( ) . map ( MatchTreeBranch :: from_candidate) . collect ( ) ,
1410
1426
otherwise_block,
1427
+ fake_borrow_temps,
1411
1428
}
1412
1429
}
1413
1430
@@ -2116,9 +2133,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
2116
2133
) -> BlockAnd < ( ) > {
2117
2134
let expr_span = self . thir [ expr_id] . span ;
2118
2135
let scrutinee = unpack ! ( block = self . lower_scrutinee( block, expr_id, expr_span) ) ;
2119
- let candidate = Candidate :: new ( scrutinee. clone ( ) , pat, false , self ) ;
2120
- let built_tree =
2121
- self . lower_match_tree ( block, expr_span, & scrutinee, pat. span , vec ! [ candidate] , true ) ;
2136
+ let built_tree = self . lower_match_tree (
2137
+ block,
2138
+ expr_span,
2139
+ & scrutinee,
2140
+ pat. span ,
2141
+ vec ! [ ( pat, HasMatchGuard :: No ) ] ,
2142
+ true ,
2143
+ ) ;
2122
2144
let [ branch] = built_tree. branches . try_into ( ) . unwrap ( ) ;
2123
2145
2124
2146
self . break_for_else ( built_tree. otherwise_block , self . source_info ( expr_span) ) ;
0 commit comments