@@ -363,36 +363,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
363363 unpack ! ( block = self . lower_scrutinee( block, scrutinee_id, scrutinee_span) ) ;
364364
365365 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
371368 . clone ( )
372369 . 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)
377373 } )
378374 . 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) ;
390375 let built_tree = self . lower_match_tree (
391376 block,
392377 scrutinee_span,
393378 & scrutinee_place,
394379 match_start_span,
395- candidates ,
380+ patterns ,
396381 false ,
397382 ) ;
398383
@@ -401,9 +386,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
401386 scrutinee_place,
402387 scrutinee_span,
403388 arms,
404- built_tree. branches ,
389+ built_tree,
405390 self . source_info ( span) ,
406- fake_borrow_temps,
407391 )
408392 }
409393
@@ -435,16 +419,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
435419 scrutinee_place_builder : PlaceBuilder < ' tcx > ,
436420 scrutinee_span : Span ,
437421 arms : impl IntoIterator < Item = & ' pat Arm < ' tcx > > ,
438- lowered_branches : impl IntoIterator < Item = MatchTreeBranch < ' tcx > > ,
422+ built_match_tree : BuiltMatchTree < ' tcx > ,
439423 outer_source_info : SourceInfo ,
440- fake_borrow_temps : Vec < ( Place < ' tcx > , Local , FakeBorrowKind ) > ,
441424 ) -> BlockAnd < ( ) >
442425 where
443426 ' tcx : ' pat ,
444427 {
445428 let arm_end_blocks: Vec < BasicBlock > = arms
446429 . into_iter ( )
447- . zip ( lowered_branches )
430+ . zip ( built_match_tree . branches )
448431 . map ( |( arm, branch) | {
449432 debug ! ( "lowering arm {:?}\n corresponding branch = {:?}" , arm, branch) ;
450433
@@ -480,7 +463,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
480463 let arm_block = this. bind_pattern (
481464 outer_source_info,
482465 branch,
483- & fake_borrow_temps,
466+ & built_match_tree . fake_borrow_temps ,
484467 scrutinee_span,
485468 Some ( ( arm, match_scope) ) ,
486469 EmitStorageLive :: Yes ,
@@ -695,13 +678,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
695678 initializer : PlaceBuilder < ' tcx > ,
696679 set_match_place : bool ,
697680 ) -> BlockAnd < ( ) > {
698- let candidate = Candidate :: new ( initializer. clone ( ) , irrefutable_pat, false , self ) ;
699681 let built_tree = self . lower_match_tree (
700682 block,
701683 irrefutable_pat. span ,
702684 & initializer,
703685 irrefutable_pat. span ,
704- vec ! [ candidate ] ,
686+ vec ! [ ( irrefutable_pat , HasMatchGuard :: No ) ] ,
705687 false ,
706688 ) ;
707689 let [ branch] = built_tree. branches . try_into ( ) . unwrap ( ) ;
@@ -1077,12 +1059,15 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
10771059 fn new (
10781060 place : PlaceBuilder < ' tcx > ,
10791061 pattern : & ' pat Pat < ' tcx > ,
1080- has_guard : bool ,
1062+ has_guard : HasMatchGuard ,
10811063 cx : & mut Builder < ' _ , ' tcx > ,
10821064 ) -> Self {
10831065 // Use `FlatPat` to build simplified match pairs, then immediately
10841066 // 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+ )
10861071 }
10871072
10881073 /// Incorporates an already-simplified [`FlatPat`] into a new candidate.
@@ -1337,6 +1322,10 @@ struct MatchTreeBranch<'tcx> {
13371322struct BuiltMatchTree < ' tcx > {
13381323 branches : Vec < MatchTreeBranch < ' tcx > > ,
13391324 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 ) > ,
13401329}
13411330
13421331impl < ' tcx > MatchTreeSubBranch < ' tcx > {
@@ -1387,12 +1376,18 @@ impl<'tcx> MatchTreeBranch<'tcx> {
13871376 }
13881377}
13891378
1379+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
1380+ enum HasMatchGuard {
1381+ Yes ,
1382+ No ,
1383+ }
1384+
13901385impl < ' a , ' tcx > Builder < ' a , ' tcx > {
13911386 /// The entrypoint of the matching algorithm. Create the decision tree for the match expression,
13921387 /// starting from `block`.
13931388 ///
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 .
13961391 ///
13971392 /// `refutable` indicates whether the candidate list is refutable (for `if let` and `let else`)
13981393 /// 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> {
14031398 scrutinee_span : Span ,
14041399 scrutinee_place_builder : & PlaceBuilder < ' tcx > ,
14051400 match_start_span : Span ,
1406- mut candidates : Vec < Candidate < ' pat , ' tcx > > ,
1401+ patterns : Vec < ( & ' pat Pat < ' tcx > , HasMatchGuard ) > ,
14071402 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+
14091425 // This will generate code to test scrutinee_place and branch to the appropriate arm block.
14101426 // If none of the arms match, we branch to `otherwise_block`. When lowering a `match`
14111427 // expression, exhaustiveness checking ensures that this block is unreachable.
@@ -1484,6 +1500,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
14841500 BuiltMatchTree {
14851501 branches : candidates. into_iter ( ) . map ( MatchTreeBranch :: from_candidate) . collect ( ) ,
14861502 otherwise_block,
1503+ fake_borrow_temps,
14871504 }
14881505 }
14891506
@@ -2167,9 +2184,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
21672184 ) -> BlockAnd < ( ) > {
21682185 let expr_span = self . thir [ expr_id] . span ;
21692186 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+ ) ;
21732195 let [ branch] = built_tree. branches . try_into ( ) . unwrap ( ) ;
21742196
21752197 self . break_for_else ( built_tree. otherwise_block , self . source_info ( expr_span) ) ;
0 commit comments