@@ -363,36 +363,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
363
363
unpack ! ( block = self . lower_scrutinee( block, scrutinee_id, scrutinee_span) ) ;
364
364
365
365
let arms = arms. iter ( ) . map ( |arm| & self . thir [ * arm] ) ;
366
- // Assemble the initial list of candidates. These top-level candidates are 1:1 with the
367
- // original match arms, but other parts of match lowering also introduce subcandidates (for
368
- // sub-or-patterns). So inside the algorithm, the candidates list may not correspond to
369
- // match arms directly.
370
- let candidates: Vec < _ > = arms
366
+ let match_start_span = span. shrink_to_lo ( ) . to ( scrutinee_span) ;
367
+ let patterns = arms
371
368
. clone ( )
372
369
. map ( |arm| {
373
- let arm_has_guard = arm. guard . is_some ( ) ;
374
- let arm_candidate =
375
- Candidate :: new ( scrutinee_place. clone ( ) , & arm. pattern , arm_has_guard, self ) ;
376
- arm_candidate
370
+ let has_match_guard =
371
+ if arm. guard . is_some ( ) { HasMatchGuard :: Yes } else { HasMatchGuard :: No } ;
372
+ ( & * arm. pattern , has_match_guard)
377
373
} )
378
374
. collect ( ) ;
379
-
380
- // The set of places that we are creating fake borrows of. If there are no match guards then
381
- // we don't need any fake borrows, so don't track them.
382
- let match_has_guard = candidates. iter ( ) . any ( |candidate| candidate. has_guard ) ;
383
- let fake_borrow_temps: Vec < ( Place < ' tcx > , Local , FakeBorrowKind ) > = if match_has_guard {
384
- util:: collect_fake_borrows ( self , & candidates, scrutinee_span, scrutinee_place. base ( ) )
385
- } else {
386
- Vec :: new ( )
387
- } ;
388
-
389
- let match_start_span = span. shrink_to_lo ( ) . to ( scrutinee_span) ;
390
375
let built_tree = self . lower_match_tree (
391
376
block,
392
377
scrutinee_span,
393
378
& scrutinee_place,
394
379
match_start_span,
395
- candidates ,
380
+ patterns ,
396
381
false ,
397
382
) ;
398
383
@@ -401,9 +386,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
401
386
scrutinee_place,
402
387
scrutinee_span,
403
388
arms,
404
- built_tree. branches ,
389
+ built_tree,
405
390
self . source_info ( span) ,
406
- fake_borrow_temps,
407
391
)
408
392
}
409
393
@@ -435,16 +419,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
435
419
scrutinee_place_builder : PlaceBuilder < ' tcx > ,
436
420
scrutinee_span : Span ,
437
421
arms : impl IntoIterator < Item = & ' pat Arm < ' tcx > > ,
438
- lowered_branches : impl IntoIterator < Item = MatchTreeBranch < ' tcx > > ,
422
+ built_match_tree : BuiltMatchTree < ' tcx > ,
439
423
outer_source_info : SourceInfo ,
440
- fake_borrow_temps : Vec < ( Place < ' tcx > , Local , FakeBorrowKind ) > ,
441
424
) -> BlockAnd < ( ) >
442
425
where
443
426
' tcx : ' pat ,
444
427
{
445
428
let arm_end_blocks: Vec < BasicBlock > = arms
446
429
. into_iter ( )
447
- . zip ( lowered_branches )
430
+ . zip ( built_match_tree . branches )
448
431
. map ( |( arm, branch) | {
449
432
debug ! ( "lowering arm {:?}\n corresponding branch = {:?}" , arm, branch) ;
450
433
@@ -480,7 +463,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
480
463
let arm_block = this. bind_pattern (
481
464
outer_source_info,
482
465
branch,
483
- & fake_borrow_temps,
466
+ & built_match_tree . fake_borrow_temps ,
484
467
scrutinee_span,
485
468
Some ( ( arm, match_scope) ) ,
486
469
EmitStorageLive :: Yes ,
@@ -695,13 +678,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
695
678
initializer : PlaceBuilder < ' tcx > ,
696
679
set_match_place : bool ,
697
680
) -> BlockAnd < ( ) > {
698
- let candidate = Candidate :: new ( initializer. clone ( ) , irrefutable_pat, false , self ) ;
699
681
let built_tree = self . lower_match_tree (
700
682
block,
701
683
irrefutable_pat. span ,
702
684
& initializer,
703
685
irrefutable_pat. span ,
704
- vec ! [ candidate ] ,
686
+ vec ! [ ( irrefutable_pat , HasMatchGuard :: No ) ] ,
705
687
false ,
706
688
) ;
707
689
let [ branch] = built_tree. branches . try_into ( ) . unwrap ( ) ;
@@ -1077,12 +1059,15 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
1077
1059
fn new (
1078
1060
place : PlaceBuilder < ' tcx > ,
1079
1061
pattern : & ' pat Pat < ' tcx > ,
1080
- has_guard : bool ,
1062
+ has_guard : HasMatchGuard ,
1081
1063
cx : & mut Builder < ' _ , ' tcx > ,
1082
1064
) -> Self {
1083
1065
// Use `FlatPat` to build simplified match pairs, then immediately
1084
1066
// incorporate them into a new candidate.
1085
- Self :: from_flat_pat ( FlatPat :: new ( place, pattern, cx) , has_guard)
1067
+ Self :: from_flat_pat (
1068
+ FlatPat :: new ( place, pattern, cx) ,
1069
+ matches ! ( has_guard, HasMatchGuard :: Yes ) ,
1070
+ )
1086
1071
}
1087
1072
1088
1073
/// Incorporates an already-simplified [`FlatPat`] into a new candidate.
@@ -1337,6 +1322,10 @@ struct MatchTreeBranch<'tcx> {
1337
1322
struct BuiltMatchTree < ' tcx > {
1338
1323
branches : Vec < MatchTreeBranch < ' tcx > > ,
1339
1324
otherwise_block : BasicBlock ,
1325
+ /// If any of the branches had a guard, we collect here the places and locals to fakely borrow
1326
+ /// to ensure match guards can't modify the values as we match them. For more details, see
1327
+ /// [`util::collect_fake_borrows`].
1328
+ fake_borrow_temps : Vec < ( Place < ' tcx > , Local , FakeBorrowKind ) > ,
1340
1329
}
1341
1330
1342
1331
impl < ' tcx > MatchTreeSubBranch < ' tcx > {
@@ -1387,12 +1376,18 @@ impl<'tcx> MatchTreeBranch<'tcx> {
1387
1376
}
1388
1377
}
1389
1378
1379
+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
1380
+ enum HasMatchGuard {
1381
+ Yes ,
1382
+ No ,
1383
+ }
1384
+
1390
1385
impl < ' a , ' tcx > Builder < ' a , ' tcx > {
1391
1386
/// The entrypoint of the matching algorithm. Create the decision tree for the match expression,
1392
1387
/// starting from `block`.
1393
1388
///
1394
- /// Modifies `candidates` to store the bindings and type ascriptions for
1395
- /// that candidate .
1389
+ /// `patterns` is a list of patterns, one for each arm. The associated boolean indicates whether
1390
+ /// the arm has a guard .
1396
1391
///
1397
1392
/// `refutable` indicates whether the candidate list is refutable (for `if let` and `let else`)
1398
1393
/// or not (for `let` and `match`). In the refutable case we return the block to which we branch
@@ -1403,9 +1398,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1403
1398
scrutinee_span : Span ,
1404
1399
scrutinee_place_builder : & PlaceBuilder < ' tcx > ,
1405
1400
match_start_span : Span ,
1406
- mut candidates : Vec < Candidate < ' pat , ' tcx > > ,
1401
+ patterns : Vec < ( & ' pat Pat < ' tcx > , HasMatchGuard ) > ,
1407
1402
refutable : bool ,
1408
- ) -> BuiltMatchTree < ' tcx > {
1403
+ ) -> BuiltMatchTree < ' tcx >
1404
+ where
1405
+ ' tcx : ' pat ,
1406
+ {
1407
+ // Assemble the initial list of candidates. These top-level candidates are 1:1 with the
1408
+ // input patterns, but other parts of match lowering also introduce subcandidates (for
1409
+ // sub-or-patterns). So inside the algorithm, the candidates list may not correspond to
1410
+ // match arms directly.
1411
+ let mut candidates: Vec < Candidate < ' _ , ' _ > > = patterns
1412
+ . into_iter ( )
1413
+ . map ( |( pat, has_guard) | {
1414
+ Candidate :: new ( scrutinee_place_builder. clone ( ) , pat, has_guard, self )
1415
+ } )
1416
+ . collect ( ) ;
1417
+
1418
+ let fake_borrow_temps = util:: collect_fake_borrows (
1419
+ self ,
1420
+ & candidates,
1421
+ scrutinee_span,
1422
+ scrutinee_place_builder. base ( ) ,
1423
+ ) ;
1424
+
1409
1425
// This will generate code to test scrutinee_place and branch to the appropriate arm block.
1410
1426
// If none of the arms match, we branch to `otherwise_block`. When lowering a `match`
1411
1427
// expression, exhaustiveness checking ensures that this block is unreachable.
@@ -1484,6 +1500,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1484
1500
BuiltMatchTree {
1485
1501
branches : candidates. into_iter ( ) . map ( MatchTreeBranch :: from_candidate) . collect ( ) ,
1486
1502
otherwise_block,
1503
+ fake_borrow_temps,
1487
1504
}
1488
1505
}
1489
1506
@@ -2167,9 +2184,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
2167
2184
) -> BlockAnd < ( ) > {
2168
2185
let expr_span = self . thir [ expr_id] . span ;
2169
2186
let scrutinee = unpack ! ( block = self . lower_scrutinee( block, expr_id, expr_span) ) ;
2170
- let candidate = Candidate :: new ( scrutinee. clone ( ) , pat, false , self ) ;
2171
- let built_tree =
2172
- self . lower_match_tree ( block, expr_span, & scrutinee, pat. span , vec ! [ candidate] , true ) ;
2187
+ let built_tree = self . lower_match_tree (
2188
+ block,
2189
+ expr_span,
2190
+ & scrutinee,
2191
+ pat. span ,
2192
+ vec ! [ ( pat, HasMatchGuard :: No ) ] ,
2193
+ true ,
2194
+ ) ;
2173
2195
let [ branch] = built_tree. branches . try_into ( ) . unwrap ( ) ;
2174
2196
2175
2197
self . break_for_else ( built_tree. otherwise_block , self . source_info ( expr_span) ) ;
0 commit comments