@@ -321,20 +321,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
321321 // The set of places that we are creating fake borrows of. If there are
322322 // no match guards then we don't need any fake borrows, so don't track
323323 // them.
324- let mut fake_borrows = match_has_guard. then ( FxIndexSet :: default) ;
324+ let fake_borrows = match_has_guard
325+ . then ( || util:: FakeBorrowCollector :: collect_fake_borrows ( self , candidates) ) ;
325326
326327 let otherwise_block = self . cfg . start_new_block ( ) ;
327328
328329 // This will generate code to test scrutinee_place and
329330 // branch to the appropriate arm block
330- self . match_candidates (
331- match_start_span,
332- scrutinee_span,
333- block,
334- otherwise_block,
335- candidates,
336- & mut fake_borrows,
337- ) ;
331+ self . match_candidates ( match_start_span, scrutinee_span, block, otherwise_block, candidates) ;
338332
339333 // See the doc comment on `match_candidates` for why we may have an
340334 // otherwise block. Match checking will ensure this is actually
@@ -944,6 +938,40 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
944938 }
945939}
946940
941+ /// A pattern in a form suitable for generating code.
942+ #[ derive( Debug , Clone ) ]
943+ struct FlatPat < ' pat , ' tcx > {
944+ /// [`Span`] of the original pattern.
945+ span : Span ,
946+
947+ /// To match the pattern, all of these must be satisfied...
948+ // Invariant: all the `MatchPair`s are recursively simplified.
949+ // Invariant: or-patterns must be sorted to the end.
950+ match_pairs : Vec < MatchPair < ' pat , ' tcx > > ,
951+
952+ /// ...these bindings established...
953+ bindings : Vec < Binding < ' tcx > > ,
954+
955+ /// ...and these types asserted.
956+ ascriptions : Vec < Ascription < ' tcx > > ,
957+ }
958+
959+ impl < ' tcx , ' pat > FlatPat < ' pat , ' tcx > {
960+ fn new (
961+ place : PlaceBuilder < ' tcx > ,
962+ pattern : & ' pat Pat < ' tcx > ,
963+ cx : & mut Builder < ' _ , ' tcx > ,
964+ ) -> Self {
965+ let mut match_pairs = vec ! [ MatchPair :: new( place, pattern, cx) ] ;
966+ let mut bindings = Vec :: new ( ) ;
967+ let mut ascriptions = Vec :: new ( ) ;
968+
969+ cx. simplify_match_pairs ( & mut match_pairs, & mut bindings, & mut ascriptions) ;
970+
971+ FlatPat { span : pattern. span , match_pairs, bindings, ascriptions }
972+ }
973+ }
974+
947975#[ derive( Debug ) ]
948976struct Candidate < ' pat , ' tcx > {
949977 /// [`Span`] of the original pattern that gave rise to this candidate.
@@ -958,11 +986,11 @@ struct Candidate<'pat, 'tcx> {
958986 match_pairs : Vec < MatchPair < ' pat , ' tcx > > ,
959987
960988 /// ...these bindings established...
961- // Invariant: not mutated outside `Candidate::new()` .
989+ // Invariant: not mutated after candidate creation .
962990 bindings : Vec < Binding < ' tcx > > ,
963991
964992 /// ...and these types asserted...
965- // Invariant: not mutated outside `Candidate::new()` .
993+ // Invariant: not mutated after candidate creation .
966994 ascriptions : Vec < Ascription < ' tcx > > ,
967995
968996 /// ...and if this is non-empty, one of these subcandidates also has to match...
@@ -984,25 +1012,21 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
9841012 has_guard : bool ,
9851013 cx : & mut Builder < ' _ , ' tcx > ,
9861014 ) -> Self {
987- let mut candidate = Candidate {
988- span : pattern. span ,
1015+ Self :: from_flat_pat ( FlatPat :: new ( place, pattern, cx) , has_guard)
1016+ }
1017+
1018+ fn from_flat_pat ( flat_pat : FlatPat < ' pat , ' tcx > , has_guard : bool ) -> Self {
1019+ Candidate {
1020+ span : flat_pat. span ,
1021+ match_pairs : flat_pat. match_pairs ,
1022+ bindings : flat_pat. bindings ,
1023+ ascriptions : flat_pat. ascriptions ,
9891024 has_guard,
990- match_pairs : vec ! [ MatchPair :: new( place, pattern, cx) ] ,
991- bindings : Vec :: new ( ) ,
992- ascriptions : Vec :: new ( ) ,
9931025 subcandidates : Vec :: new ( ) ,
9941026 otherwise_block : None ,
9951027 pre_binding_block : None ,
9961028 next_candidate_pre_binding_block : None ,
997- } ;
998-
999- cx. simplify_match_pairs (
1000- & mut candidate. match_pairs ,
1001- & mut candidate. bindings ,
1002- & mut candidate. ascriptions ,
1003- ) ;
1004-
1005- candidate
1029+ }
10061030 }
10071031
10081032 /// Visit the leaf candidates (those with no subcandidates) contained in
@@ -1065,7 +1089,7 @@ enum TestCase<'pat, 'tcx> {
10651089 Constant { value : mir:: Const < ' tcx > } ,
10661090 Range ( & ' pat PatRange < ' tcx > ) ,
10671091 Slice { len : usize , variable_length : bool } ,
1068- Or ,
1092+ Or { pats : Box < [ FlatPat < ' pat , ' tcx > ] > } ,
10691093}
10701094
10711095#[ derive( Debug , Clone ) ]
@@ -1208,19 +1232,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
12081232 ///
12091233 /// Note how we test `x` twice. This is the tradeoff of backtracking automata: we prefer smaller
12101234 /// code size at the expense of non-optimal code paths.
1211- #[ instrument( skip( self , fake_borrows ) , level = "debug" ) ]
1235+ #[ instrument( skip( self ) , level = "debug" ) ]
12121236 fn match_candidates < ' pat > (
12131237 & mut self ,
12141238 span : Span ,
12151239 scrutinee_span : Span ,
12161240 start_block : BasicBlock ,
12171241 otherwise_block : BasicBlock ,
12181242 candidates : & mut [ & mut Candidate < ' pat , ' tcx > ] ,
1219- fake_borrows : & mut Option < FxIndexSet < Place < ' tcx > > > ,
12201243 ) {
12211244 let mut split_or_candidate = false ;
12221245 for candidate in & mut * candidates {
1223- if let [ MatchPair { pattern : Pat { kind : PatKind :: Or { pats } , .. } , place , .. } ] =
1246+ if let [ MatchPair { test_case : TestCase :: Or { pats, .. } , .. } ] =
12241247 & * candidate. match_pairs
12251248 {
12261249 // Split a candidate in which the only match-pair is an or-pattern into multiple
@@ -1232,8 +1255,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
12321255 // }
12331256 //
12341257 // only generates a single switch.
1235- candidate. subcandidates =
1236- self . create_or_subcandidates ( place, pats, candidate. has_guard ) ;
1258+ candidate. subcandidates = self . create_or_subcandidates ( pats, candidate. has_guard ) ;
12371259 candidate. match_pairs . pop ( ) ;
12381260 split_or_candidate = true ;
12391261 }
@@ -1254,7 +1276,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
12541276 start_block,
12551277 otherwise_block,
12561278 & mut * new_candidates,
1257- fake_borrows,
12581279 ) ;
12591280 } else {
12601281 self . match_simplified_candidates (
@@ -1263,7 +1284,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
12631284 start_block,
12641285 otherwise_block,
12651286 candidates,
1266- fake_borrows,
12671287 ) ;
12681288 }
12691289 } ) ;
@@ -1276,7 +1296,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
12761296 mut start_block : BasicBlock ,
12771297 otherwise_block : BasicBlock ,
12781298 candidates : & mut [ & mut Candidate < ' _ , ' tcx > ] ,
1279- fake_borrows : & mut Option < FxIndexSet < Place < ' tcx > > > ,
12801299 ) {
12811300 match candidates {
12821301 [ ] => {
@@ -1288,14 +1307,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
12881307 [ first, remaining @ ..] if first. match_pairs . is_empty ( ) => {
12891308 // The first candidate has satisfied all its match pairs; we link it up and continue
12901309 // with the remaining candidates.
1291- start_block = self . select_matched_candidate ( first, start_block, fake_borrows ) ;
1310+ start_block = self . select_matched_candidate ( first, start_block) ;
12921311 self . match_simplified_candidates (
12931312 span,
12941313 scrutinee_span,
12951314 start_block,
12961315 otherwise_block,
12971316 remaining,
1298- fake_borrows,
12991317 )
13001318 }
13011319 candidates => {
@@ -1306,7 +1324,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
13061324 candidates,
13071325 start_block,
13081326 otherwise_block,
1309- fake_borrows,
13101327 ) ;
13111328 }
13121329 }
@@ -1341,43 +1358,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
13411358 & mut self ,
13421359 candidate : & mut Candidate < ' _ , ' tcx > ,
13431360 start_block : BasicBlock ,
1344- fake_borrows : & mut Option < FxIndexSet < Place < ' tcx > > > ,
13451361 ) -> BasicBlock {
13461362 assert ! ( candidate. otherwise_block. is_none( ) ) ;
13471363 assert ! ( candidate. pre_binding_block. is_none( ) ) ;
13481364 assert ! ( candidate. subcandidates. is_empty( ) ) ;
13491365
1350- if let Some ( fake_borrows) = fake_borrows {
1351- // Insert a borrows of prefixes of places that are bound and are
1352- // behind a dereference projection.
1353- //
1354- // These borrows are taken to avoid situations like the following:
1355- //
1356- // match x[10] {
1357- // _ if { x = &[0]; false } => (),
1358- // y => (), // Out of bounds array access!
1359- // }
1360- //
1361- // match *x {
1362- // // y is bound by reference in the guard and then by copy in the
1363- // // arm, so y is 2 in the arm!
1364- // y if { y == 1 && (x = &2) == () } => y,
1365- // _ => 3,
1366- // }
1367- for Binding { source, .. } in & candidate. bindings {
1368- if let Some ( i) =
1369- source. projection . iter ( ) . rposition ( |elem| elem == ProjectionElem :: Deref )
1370- {
1371- let proj_base = & source. projection [ ..i] ;
1372-
1373- fake_borrows. insert ( Place {
1374- local : source. local ,
1375- projection : self . tcx . mk_place_elems ( proj_base) ,
1376- } ) ;
1377- }
1378- }
1379- }
1380-
13811366 candidate. pre_binding_block = Some ( start_block) ;
13821367 let otherwise_block = self . cfg . start_new_block ( ) ;
13831368 if candidate. has_guard {
@@ -1448,38 +1433,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
14481433 candidates : & mut [ & mut Candidate < ' _ , ' tcx > ] ,
14491434 start_block : BasicBlock ,
14501435 otherwise_block : BasicBlock ,
1451- fake_borrows : & mut Option < FxIndexSet < Place < ' tcx > > > ,
14521436 ) {
14531437 let ( first_candidate, remaining_candidates) = candidates. split_first_mut ( ) . unwrap ( ) ;
14541438 assert ! ( first_candidate. subcandidates. is_empty( ) ) ;
1455- if !matches ! ( first_candidate. match_pairs[ 0 ] . pattern. kind, PatKind :: Or { .. } ) {
1456- self . test_candidates (
1457- span,
1458- scrutinee_span,
1459- candidates,
1460- start_block,
1461- otherwise_block,
1462- fake_borrows,
1463- ) ;
1439+ if !matches ! ( first_candidate. match_pairs[ 0 ] . test_case, TestCase :: Or { .. } ) {
1440+ self . test_candidates ( span, scrutinee_span, candidates, start_block, otherwise_block) ;
14641441 return ;
14651442 }
14661443
14671444 let match_pairs = mem:: take ( & mut first_candidate. match_pairs ) ;
14681445 let ( first_match_pair, remaining_match_pairs) = match_pairs. split_first ( ) . unwrap ( ) ;
1469- let PatKind :: Or { ref pats } = & first_match_pair. pattern . kind else { unreachable ! ( ) } ;
1446+ let TestCase :: Or { ref pats } = & first_match_pair. test_case else { unreachable ! ( ) } ;
14701447
14711448 let remainder_start = self . cfg . start_new_block ( ) ;
14721449 let or_span = first_match_pair. pattern . span ;
14731450 // Test the alternatives of this or-pattern.
1474- self . test_or_pattern (
1475- first_candidate,
1476- start_block,
1477- remainder_start,
1478- pats,
1479- or_span,
1480- & first_match_pair. place ,
1481- fake_borrows,
1482- ) ;
1451+ self . test_or_pattern ( first_candidate, start_block, remainder_start, pats, or_span) ;
14831452
14841453 if !remaining_match_pairs. is_empty ( ) {
14851454 // If more match pairs remain, test them after each subcandidate.
@@ -1500,7 +1469,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
15001469 & mut [ leaf_candidate] ,
15011470 or_start,
15021471 or_otherwise,
1503- fake_borrows,
15041472 ) ;
15051473 } ) ;
15061474 }
@@ -1512,28 +1480,26 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
15121480 remainder_start,
15131481 otherwise_block,
15141482 remaining_candidates,
1515- fake_borrows,
15161483 ) ;
15171484 }
15181485
15191486 #[ instrument(
1520- skip( self , start_block, otherwise_block, or_span, place , fake_borrows , candidate, pats) ,
1487+ skip( self , start_block, otherwise_block, or_span, candidate, pats) ,
15211488 level = "debug"
15221489 ) ]
15231490 fn test_or_pattern < ' pat > (
15241491 & mut self ,
15251492 candidate : & mut Candidate < ' pat , ' tcx > ,
15261493 start_block : BasicBlock ,
15271494 otherwise_block : BasicBlock ,
1528- pats : & ' pat [ Box < Pat < ' tcx > > ] ,
1495+ pats : & [ FlatPat < ' pat , ' tcx > ] ,
15291496 or_span : Span ,
1530- place : & PlaceBuilder < ' tcx > ,
1531- fake_borrows : & mut Option < FxIndexSet < Place < ' tcx > > > ,
15321497 ) {
15331498 debug ! ( "candidate={:#?}\n pats={:#?}" , candidate, pats) ;
15341499 let mut or_candidates: Vec < _ > = pats
15351500 . iter ( )
1536- . map ( |pat| Candidate :: new ( place. clone ( ) , pat, candidate. has_guard , self ) )
1501+ . cloned ( )
1502+ . map ( |flat_pat| Candidate :: from_flat_pat ( flat_pat, candidate. has_guard ) )
15371503 . collect ( ) ;
15381504 let mut or_candidate_refs: Vec < _ > = or_candidates. iter_mut ( ) . collect ( ) ;
15391505 self . match_candidates (
@@ -1542,7 +1508,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
15421508 start_block,
15431509 otherwise_block,
15441510 & mut or_candidate_refs,
1545- fake_borrows,
15461511 ) ;
15471512 candidate. subcandidates = or_candidates;
15481513 self . merge_trivial_subcandidates ( candidate, self . source_info ( or_span) ) ;
@@ -1602,7 +1567,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
16021567 fn pick_test (
16031568 & mut self ,
16041569 candidates : & mut [ & mut Candidate < ' _ , ' tcx > ] ,
1605- fake_borrows : & mut Option < FxIndexSet < Place < ' tcx > > > ,
16061570 ) -> ( PlaceBuilder < ' tcx > , Test < ' tcx > ) {
16071571 // Extract the match-pair from the highest priority candidate
16081572 let match_pair = & candidates. first ( ) . unwrap ( ) . match_pairs [ 0 ] ;
@@ -1631,13 +1595,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
16311595 _ => { }
16321596 }
16331597
1634- // Insert a Shallow borrow of any places that is switched on.
1635- if let Some ( fb) = fake_borrows
1636- && let Some ( resolved_place) = match_place. try_to_place ( self )
1637- {
1638- fb. insert ( resolved_place) ;
1639- }
1640-
16411598 ( match_place, test)
16421599 }
16431600
@@ -1811,10 +1768,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
18111768 candidates : & ' b mut [ & ' c mut Candidate < ' pat , ' tcx > ] ,
18121769 start_block : BasicBlock ,
18131770 otherwise_block : BasicBlock ,
1814- fake_borrows : & mut Option < FxIndexSet < Place < ' tcx > > > ,
18151771 ) {
18161772 // Extract the match-pair from the highest priority candidate and build a test from it.
1817- let ( match_place, test) = self . pick_test ( candidates, fake_borrows ) ;
1773+ let ( match_place, test) = self . pick_test ( candidates) ;
18181774
18191775 // For each of the N possible test outcomes, build the vector of candidates that applies if
18201776 // the test has that particular outcome.
@@ -1831,7 +1787,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
18311787 remainder_start,
18321788 otherwise_block,
18331789 remaining_candidates,
1834- fake_borrows,
18351790 ) ;
18361791 remainder_start
18371792 } else {
@@ -1853,7 +1808,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
18531808 candidate_start,
18541809 remainder_start,
18551810 & mut * candidates,
1856- fake_borrows,
18571811 ) ;
18581812 candidate_start
18591813 } else {
0 commit comments