@@ -366,36 +366,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
366
366
unpack ! ( block = self . lower_scrutinee( block, scrutinee_id, scrutinee_span) ) ;
367
367
368
368
let arms = arms. iter ( ) . map ( |arm| & self . thir [ * arm] ) ;
369
- // Assemble the initial list of candidates. These top-level candidates are 1:1 with the
370
- // original match arms, but other parts of match lowering also introduce subcandidates (for
371
- // sub-or-patterns). So inside the algorithm, the candidates list may not correspond to
372
- // match arms directly.
373
- let candidates: Vec < _ > = arms
369
+ let match_start_span = span. shrink_to_lo ( ) . to ( scrutinee_span) ;
370
+ let patterns = arms
374
371
. clone ( )
375
372
. map ( |arm| {
376
- let arm_has_guard = arm. guard . is_some ( ) ;
377
- let arm_candidate =
378
- Candidate :: new ( scrutinee_place. clone ( ) , & arm. pattern , arm_has_guard, self ) ;
379
- arm_candidate
373
+ let has_match_guard =
374
+ if arm. guard . is_some ( ) { HasMatchGuard :: Yes } else { HasMatchGuard :: No } ;
375
+ ( & * arm. pattern , has_match_guard)
380
376
} )
381
377
. collect ( ) ;
382
-
383
- // The set of places that we are creating fake borrows of. If there are no match guards then
384
- // we don't need any fake borrows, so don't track them.
385
- let match_has_guard = candidates. iter ( ) . any ( |candidate| candidate. has_guard ) ;
386
- let fake_borrow_temps: Vec < ( Place < ' tcx > , Local , FakeBorrowKind ) > = if match_has_guard {
387
- util:: collect_fake_borrows ( self , & candidates, scrutinee_span, scrutinee_place. base ( ) )
388
- } else {
389
- Vec :: new ( )
390
- } ;
391
-
392
- let match_start_span = span. shrink_to_lo ( ) . to ( scrutinee_span) ;
393
378
let built_tree = self . lower_match_tree (
394
379
block,
395
380
scrutinee_span,
396
381
& scrutinee_place,
397
382
match_start_span,
398
- candidates ,
383
+ patterns ,
399
384
false ,
400
385
) ;
401
386
@@ -404,9 +389,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
404
389
scrutinee_place,
405
390
scrutinee_span,
406
391
arms,
407
- built_tree. branches ,
392
+ built_tree,
408
393
self . source_info ( span) ,
409
- fake_borrow_temps,
410
394
)
411
395
}
412
396
@@ -438,16 +422,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
438
422
scrutinee_place_builder : PlaceBuilder < ' tcx > ,
439
423
scrutinee_span : Span ,
440
424
arms : impl IntoIterator < Item = & ' pat Arm < ' tcx > > ,
441
- lowered_branches : impl IntoIterator < Item = MatchTreeBranch < ' tcx > > ,
425
+ built_match_tree : BuiltMatchTree < ' tcx > ,
442
426
outer_source_info : SourceInfo ,
443
- fake_borrow_temps : Vec < ( Place < ' tcx > , Local , FakeBorrowKind ) > ,
444
427
) -> BlockAnd < ( ) >
445
428
where
446
429
' tcx : ' pat ,
447
430
{
448
431
let arm_end_blocks: Vec < BasicBlock > = arms
449
432
. into_iter ( )
450
- . zip ( lowered_branches )
433
+ . zip ( built_match_tree . branches )
451
434
. map ( |( arm, branch) | {
452
435
debug ! ( "lowering arm {:?}\n corresponding branch = {:?}" , arm, branch) ;
453
436
@@ -483,7 +466,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
483
466
let arm_block = this. bind_pattern (
484
467
outer_source_info,
485
468
branch,
486
- & fake_borrow_temps,
469
+ & built_match_tree . fake_borrow_temps ,
487
470
scrutinee_span,
488
471
Some ( ( arm, match_scope) ) ,
489
472
EmitStorageLive :: Yes ,
@@ -700,13 +683,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
700
683
initializer : PlaceBuilder < ' tcx > ,
701
684
set_match_place : bool ,
702
685
) -> BlockAnd < ( ) > {
703
- let candidate = Candidate :: new ( initializer. clone ( ) , irrefutable_pat, false , self ) ;
704
686
let built_tree = self . lower_match_tree (
705
687
block,
706
688
irrefutable_pat. span ,
707
689
& initializer,
708
690
irrefutable_pat. span ,
709
- vec ! [ candidate ] ,
691
+ vec ! [ ( irrefutable_pat , HasMatchGuard :: No ) ] ,
710
692
false ,
711
693
) ;
712
694
let [ branch] = built_tree. branches . try_into ( ) . unwrap ( ) ;
@@ -1136,12 +1118,15 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
1136
1118
fn new (
1137
1119
place : PlaceBuilder < ' tcx > ,
1138
1120
pattern : & ' pat Pat < ' tcx > ,
1139
- has_guard : bool ,
1121
+ has_guard : HasMatchGuard ,
1140
1122
cx : & mut Builder < ' _ , ' tcx > ,
1141
1123
) -> Self {
1142
1124
// Use `FlatPat` to build simplified match pairs, then immediately
1143
1125
// incorporate them into a new candidate.
1144
- Self :: from_flat_pat ( FlatPat :: new ( place, pattern, cx) , has_guard)
1126
+ Self :: from_flat_pat (
1127
+ FlatPat :: new ( place, pattern, cx) ,
1128
+ matches ! ( has_guard, HasMatchGuard :: Yes ) ,
1129
+ )
1145
1130
}
1146
1131
1147
1132
/// Incorporates an already-simplified [`FlatPat`] into a new candidate.
@@ -1437,6 +1422,10 @@ struct MatchTreeBranch<'tcx> {
1437
1422
struct BuiltMatchTree < ' tcx > {
1438
1423
branches : Vec < MatchTreeBranch < ' tcx > > ,
1439
1424
otherwise_block : BasicBlock ,
1425
+ /// If any of the branches had a guard, we collect here the places and locals to fakely borrow
1426
+ /// to ensure match guards can't modify the values as we match them. For more details, see
1427
+ /// [`util::collect_fake_borrows`].
1428
+ fake_borrow_temps : Vec < ( Place < ' tcx > , Local , FakeBorrowKind ) > ,
1440
1429
}
1441
1430
1442
1431
impl < ' tcx > MatchTreeSubBranch < ' tcx > {
@@ -1487,12 +1476,18 @@ impl<'tcx> MatchTreeBranch<'tcx> {
1487
1476
}
1488
1477
}
1489
1478
1479
+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
1480
+ enum HasMatchGuard {
1481
+ Yes ,
1482
+ No ,
1483
+ }
1484
+
1490
1485
impl < ' a , ' tcx > Builder < ' a , ' tcx > {
1491
1486
/// The entrypoint of the matching algorithm. Create the decision tree for the match expression,
1492
1487
/// starting from `block`.
1493
1488
///
1494
- /// Modifies `candidates` to store the bindings and type ascriptions for
1495
- /// that candidate .
1489
+ /// `patterns` is a list of patterns, one for each arm. The associated boolean indicates whether
1490
+ /// the arm has a guard .
1496
1491
///
1497
1492
/// `refutable` indicates whether the candidate list is refutable (for `if let` and `let else`)
1498
1493
/// or not (for `let` and `match`). In the refutable case we return the block to which we branch
@@ -1503,9 +1498,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1503
1498
scrutinee_span : Span ,
1504
1499
scrutinee_place_builder : & PlaceBuilder < ' tcx > ,
1505
1500
match_start_span : Span ,
1506
- mut candidates : Vec < Candidate < ' pat , ' tcx > > ,
1501
+ patterns : Vec < ( & ' pat Pat < ' tcx > , HasMatchGuard ) > ,
1507
1502
refutable : bool ,
1508
- ) -> BuiltMatchTree < ' tcx > {
1503
+ ) -> BuiltMatchTree < ' tcx >
1504
+ where
1505
+ ' tcx : ' pat ,
1506
+ {
1507
+ // Assemble the initial list of candidates. These top-level candidates are 1:1 with the
1508
+ // input patterns, but other parts of match lowering also introduce subcandidates (for
1509
+ // sub-or-patterns). So inside the algorithm, the candidates list may not correspond to
1510
+ // match arms directly.
1511
+ let mut candidates: Vec < Candidate < ' _ , ' _ > > = patterns
1512
+ . into_iter ( )
1513
+ . map ( |( pat, has_guard) | {
1514
+ Candidate :: new ( scrutinee_place_builder. clone ( ) , pat, has_guard, self )
1515
+ } )
1516
+ . collect ( ) ;
1517
+
1518
+ let fake_borrow_temps = util:: collect_fake_borrows (
1519
+ self ,
1520
+ & candidates,
1521
+ scrutinee_span,
1522
+ scrutinee_place_builder. base ( ) ,
1523
+ ) ;
1524
+
1509
1525
// This will generate code to test scrutinee_place and branch to the appropriate arm block.
1510
1526
// If none of the arms match, we branch to `otherwise_block`. When lowering a `match`
1511
1527
// expression, exhaustiveness checking ensures that this block is unreachable.
@@ -1584,6 +1600,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1584
1600
BuiltMatchTree {
1585
1601
branches : candidates. into_iter ( ) . map ( MatchTreeBranch :: from_candidate) . collect ( ) ,
1586
1602
otherwise_block,
1603
+ fake_borrow_temps,
1587
1604
}
1588
1605
}
1589
1606
@@ -2334,9 +2351,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
2334
2351
) -> BlockAnd < ( ) > {
2335
2352
let expr_span = self . thir [ expr_id] . span ;
2336
2353
let scrutinee = unpack ! ( block = self . lower_scrutinee( block, expr_id, expr_span) ) ;
2337
- let candidate = Candidate :: new ( scrutinee. clone ( ) , pat, false , self ) ;
2338
- let built_tree =
2339
- self . lower_match_tree ( block, expr_span, & scrutinee, pat. span , vec ! [ candidate] , true ) ;
2354
+ let built_tree = self . lower_match_tree (
2355
+ block,
2356
+ expr_span,
2357
+ & scrutinee,
2358
+ pat. span ,
2359
+ vec ! [ ( pat, HasMatchGuard :: No ) ] ,
2360
+ true ,
2361
+ ) ;
2340
2362
let [ branch] = built_tree. branches . try_into ( ) . unwrap ( ) ;
2341
2363
2342
2364
self . break_for_else ( built_tree. otherwise_block , self . source_info ( expr_span) ) ;
0 commit comments