@@ -315,20 +315,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
315
315
// The set of places that we are creating fake borrows of. If there are
316
316
// no match guards then we don't need any fake borrows, so don't track
317
317
// them.
318
- let mut fake_borrows = match_has_guard. then ( FxIndexSet :: default) ;
318
+ let fake_borrows = match_has_guard
319
+ . then ( || util:: FakeBorrowCollector :: collect_fake_borrows ( self , candidates) ) ;
319
320
320
321
let otherwise_block = self . cfg . start_new_block ( ) ;
321
322
322
323
// This will generate code to test scrutinee_place and
323
324
// branch to the appropriate arm block
324
- self . match_candidates (
325
- match_start_span,
326
- scrutinee_span,
327
- block,
328
- otherwise_block,
329
- candidates,
330
- & mut fake_borrows,
331
- ) ;
325
+ self . match_candidates ( match_start_span, scrutinee_span, block, otherwise_block, candidates) ;
332
326
333
327
// See the doc comment on `match_candidates` for why we may have an
334
328
// otherwise block. Match checking will ensure this is actually
@@ -938,6 +932,40 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
938
932
}
939
933
}
940
934
935
+ /// A pattern in a form suitable for generating code.
936
+ #[ derive( Debug , Clone ) ]
937
+ struct FlatPat < ' pat , ' tcx > {
938
+ /// [`Span`] of the original pattern.
939
+ span : Span ,
940
+
941
+ /// To match the pattern, all of these must be satisfied...
942
+ // Invariant: all the `MatchPair`s are recursively simplified.
943
+ // Invariant: or-patterns must be sorted to the end.
944
+ match_pairs : Vec < MatchPair < ' pat , ' tcx > > ,
945
+
946
+ /// ...these bindings established...
947
+ bindings : Vec < Binding < ' tcx > > ,
948
+
949
+ /// ...and these types asserted.
950
+ ascriptions : Vec < Ascription < ' tcx > > ,
951
+ }
952
+
953
+ impl < ' tcx , ' pat > FlatPat < ' pat , ' tcx > {
954
+ fn new (
955
+ place : PlaceBuilder < ' tcx > ,
956
+ pattern : & ' pat Pat < ' tcx > ,
957
+ cx : & mut Builder < ' _ , ' tcx > ,
958
+ ) -> Self {
959
+ let mut match_pairs = vec ! [ MatchPair :: new( place, pattern, cx) ] ;
960
+ let mut bindings = Vec :: new ( ) ;
961
+ let mut ascriptions = Vec :: new ( ) ;
962
+
963
+ cx. simplify_match_pairs ( & mut match_pairs, & mut bindings, & mut ascriptions) ;
964
+
965
+ FlatPat { span : pattern. span , match_pairs, bindings, ascriptions }
966
+ }
967
+ }
968
+
941
969
#[ derive( Debug ) ]
942
970
struct Candidate < ' pat , ' tcx > {
943
971
/// [`Span`] of the original pattern that gave rise to this candidate.
@@ -952,11 +980,11 @@ struct Candidate<'pat, 'tcx> {
952
980
match_pairs : Vec < MatchPair < ' pat , ' tcx > > ,
953
981
954
982
/// ...these bindings established...
955
- // Invariant: not mutated outside `Candidate::new()` .
983
+ // Invariant: not mutated after candidate creation .
956
984
bindings : Vec < Binding < ' tcx > > ,
957
985
958
986
/// ...and these types asserted...
959
- // Invariant: not mutated outside `Candidate::new()` .
987
+ // Invariant: not mutated after candidate creation .
960
988
ascriptions : Vec < Ascription < ' tcx > > ,
961
989
962
990
/// ...and if this is non-empty, one of these subcandidates also has to match...
@@ -978,25 +1006,21 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
978
1006
has_guard : bool ,
979
1007
cx : & mut Builder < ' _ , ' tcx > ,
980
1008
) -> Self {
981
- let mut candidate = Candidate {
982
- span : pattern. span ,
1009
+ Self :: from_flat_pat ( FlatPat :: new ( place, pattern, cx) , has_guard)
1010
+ }
1011
+
1012
+ fn from_flat_pat ( flat_pat : FlatPat < ' pat , ' tcx > , has_guard : bool ) -> Self {
1013
+ Candidate {
1014
+ span : flat_pat. span ,
1015
+ match_pairs : flat_pat. match_pairs ,
1016
+ bindings : flat_pat. bindings ,
1017
+ ascriptions : flat_pat. ascriptions ,
983
1018
has_guard,
984
- match_pairs : vec ! [ MatchPair :: new( place, pattern, cx) ] ,
985
- bindings : Vec :: new ( ) ,
986
- ascriptions : Vec :: new ( ) ,
987
1019
subcandidates : Vec :: new ( ) ,
988
1020
otherwise_block : None ,
989
1021
pre_binding_block : None ,
990
1022
next_candidate_pre_binding_block : None ,
991
- } ;
992
-
993
- cx. simplify_match_pairs (
994
- & mut candidate. match_pairs ,
995
- & mut candidate. bindings ,
996
- & mut candidate. ascriptions ,
997
- ) ;
998
-
999
- candidate
1023
+ }
1000
1024
}
1001
1025
1002
1026
/// Visit the leaf candidates (those with no subcandidates) contained in
@@ -1059,7 +1083,7 @@ enum TestCase<'pat, 'tcx> {
1059
1083
Constant { value : mir:: Const < ' tcx > } ,
1060
1084
Range ( & ' pat PatRange < ' tcx > ) ,
1061
1085
Slice { len : usize , variable_length : bool } ,
1062
- Or ,
1086
+ Or { pats : Box < [ FlatPat < ' pat , ' tcx > ] > } ,
1063
1087
}
1064
1088
1065
1089
#[ derive( Debug , Clone ) ]
@@ -1205,19 +1229,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1205
1229
///
1206
1230
/// Note how we test `x` twice. This is the tradeoff of backtracking automata: we prefer smaller
1207
1231
/// code size at the expense of non-optimal code paths.
1208
- #[ instrument( skip( self , fake_borrows ) , level = "debug" ) ]
1232
+ #[ instrument( skip( self ) , level = "debug" ) ]
1209
1233
fn match_candidates < ' pat > (
1210
1234
& mut self ,
1211
1235
span : Span ,
1212
1236
scrutinee_span : Span ,
1213
1237
start_block : BasicBlock ,
1214
1238
otherwise_block : BasicBlock ,
1215
1239
candidates : & mut [ & mut Candidate < ' pat , ' tcx > ] ,
1216
- fake_borrows : & mut Option < FxIndexSet < Place < ' tcx > > > ,
1217
1240
) {
1218
1241
let mut split_or_candidate = false ;
1219
1242
for candidate in & mut * candidates {
1220
- if let [ MatchPair { pattern : Pat { kind : PatKind :: Or { pats } , .. } , place , .. } ] =
1243
+ if let [ MatchPair { test_case : TestCase :: Or { pats, .. } , .. } ] =
1221
1244
& * candidate. match_pairs
1222
1245
{
1223
1246
// Split a candidate in which the only match-pair is an or-pattern into multiple
@@ -1229,8 +1252,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1229
1252
// }
1230
1253
//
1231
1254
// only generates a single switch.
1232
- candidate. subcandidates =
1233
- self . create_or_subcandidates ( place, pats, candidate. has_guard ) ;
1255
+ candidate. subcandidates = self . create_or_subcandidates ( pats, candidate. has_guard ) ;
1234
1256
candidate. match_pairs . pop ( ) ;
1235
1257
split_or_candidate = true ;
1236
1258
}
@@ -1251,7 +1273,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1251
1273
start_block,
1252
1274
otherwise_block,
1253
1275
& mut * new_candidates,
1254
- fake_borrows,
1255
1276
) ;
1256
1277
} else {
1257
1278
self . match_simplified_candidates (
@@ -1260,7 +1281,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1260
1281
start_block,
1261
1282
otherwise_block,
1262
1283
candidates,
1263
- fake_borrows,
1264
1284
) ;
1265
1285
}
1266
1286
} ) ;
@@ -1273,7 +1293,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1273
1293
mut start_block : BasicBlock ,
1274
1294
otherwise_block : BasicBlock ,
1275
1295
candidates : & mut [ & mut Candidate < ' _ , ' tcx > ] ,
1276
- fake_borrows : & mut Option < FxIndexSet < Place < ' tcx > > > ,
1277
1296
) {
1278
1297
match candidates {
1279
1298
[ ] => {
@@ -1285,14 +1304,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1285
1304
[ first, remaining @ ..] if first. match_pairs . is_empty ( ) => {
1286
1305
// The first candidate has satisfied all its match pairs; we link it up and continue
1287
1306
// with the remaining candidates.
1288
- start_block = self . select_matched_candidate ( first, start_block, fake_borrows ) ;
1307
+ start_block = self . select_matched_candidate ( first, start_block) ;
1289
1308
self . match_simplified_candidates (
1290
1309
span,
1291
1310
scrutinee_span,
1292
1311
start_block,
1293
1312
otherwise_block,
1294
1313
remaining,
1295
- fake_borrows,
1296
1314
)
1297
1315
}
1298
1316
candidates => {
@@ -1303,7 +1321,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1303
1321
candidates,
1304
1322
start_block,
1305
1323
otherwise_block,
1306
- fake_borrows,
1307
1324
) ;
1308
1325
}
1309
1326
}
@@ -1338,43 +1355,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1338
1355
& mut self ,
1339
1356
candidate : & mut Candidate < ' _ , ' tcx > ,
1340
1357
start_block : BasicBlock ,
1341
- fake_borrows : & mut Option < FxIndexSet < Place < ' tcx > > > ,
1342
1358
) -> BasicBlock {
1343
1359
assert ! ( candidate. otherwise_block. is_none( ) ) ;
1344
1360
assert ! ( candidate. pre_binding_block. is_none( ) ) ;
1345
1361
assert ! ( candidate. subcandidates. is_empty( ) ) ;
1346
1362
1347
- if let Some ( fake_borrows) = fake_borrows {
1348
- // Insert a borrows of prefixes of places that are bound and are
1349
- // behind a dereference projection.
1350
- //
1351
- // These borrows are taken to avoid situations like the following:
1352
- //
1353
- // match x[10] {
1354
- // _ if { x = &[0]; false } => (),
1355
- // y => (), // Out of bounds array access!
1356
- // }
1357
- //
1358
- // match *x {
1359
- // // y is bound by reference in the guard and then by copy in the
1360
- // // arm, so y is 2 in the arm!
1361
- // y if { y == 1 && (x = &2) == () } => y,
1362
- // _ => 3,
1363
- // }
1364
- for Binding { source, .. } in & candidate. bindings {
1365
- if let Some ( i) =
1366
- source. projection . iter ( ) . rposition ( |elem| elem == ProjectionElem :: Deref )
1367
- {
1368
- let proj_base = & source. projection [ ..i] ;
1369
-
1370
- fake_borrows. insert ( Place {
1371
- local : source. local ,
1372
- projection : self . tcx . mk_place_elems ( proj_base) ,
1373
- } ) ;
1374
- }
1375
- }
1376
- }
1377
-
1378
1363
candidate. pre_binding_block = Some ( start_block) ;
1379
1364
let otherwise_block = self . cfg . start_new_block ( ) ;
1380
1365
if candidate. has_guard {
@@ -1445,38 +1430,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1445
1430
candidates : & mut [ & mut Candidate < ' _ , ' tcx > ] ,
1446
1431
start_block : BasicBlock ,
1447
1432
otherwise_block : BasicBlock ,
1448
- fake_borrows : & mut Option < FxIndexSet < Place < ' tcx > > > ,
1449
1433
) {
1450
1434
let ( first_candidate, remaining_candidates) = candidates. split_first_mut ( ) . unwrap ( ) ;
1451
1435
assert ! ( first_candidate. subcandidates. is_empty( ) ) ;
1452
- if !matches ! ( first_candidate. match_pairs[ 0 ] . pattern. kind, PatKind :: Or { .. } ) {
1453
- self . test_candidates (
1454
- span,
1455
- scrutinee_span,
1456
- candidates,
1457
- start_block,
1458
- otherwise_block,
1459
- fake_borrows,
1460
- ) ;
1436
+ if !matches ! ( first_candidate. match_pairs[ 0 ] . test_case, TestCase :: Or { .. } ) {
1437
+ self . test_candidates ( span, scrutinee_span, candidates, start_block, otherwise_block) ;
1461
1438
return ;
1462
1439
}
1463
1440
1464
1441
let match_pairs = mem:: take ( & mut first_candidate. match_pairs ) ;
1465
1442
let ( first_match_pair, remaining_match_pairs) = match_pairs. split_first ( ) . unwrap ( ) ;
1466
- let PatKind :: Or { ref pats } = & first_match_pair. pattern . kind else { unreachable ! ( ) } ;
1443
+ let TestCase :: Or { ref pats } = & first_match_pair. test_case else { unreachable ! ( ) } ;
1467
1444
1468
1445
let remainder_start = self . cfg . start_new_block ( ) ;
1469
1446
let or_span = first_match_pair. pattern . span ;
1470
1447
// Test the alternatives of this or-pattern.
1471
- self . test_or_pattern (
1472
- first_candidate,
1473
- start_block,
1474
- remainder_start,
1475
- pats,
1476
- or_span,
1477
- & first_match_pair. place ,
1478
- fake_borrows,
1479
- ) ;
1448
+ self . test_or_pattern ( first_candidate, start_block, remainder_start, pats, or_span) ;
1480
1449
1481
1450
if !remaining_match_pairs. is_empty ( ) {
1482
1451
// If more match pairs remain, test them after each subcandidate.
@@ -1497,7 +1466,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1497
1466
& mut [ leaf_candidate] ,
1498
1467
or_start,
1499
1468
or_otherwise,
1500
- fake_borrows,
1501
1469
) ;
1502
1470
} ) ;
1503
1471
}
@@ -1509,28 +1477,26 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1509
1477
remainder_start,
1510
1478
otherwise_block,
1511
1479
remaining_candidates,
1512
- fake_borrows,
1513
1480
) ;
1514
1481
}
1515
1482
1516
1483
#[ instrument(
1517
- skip( self , start_block, otherwise_block, or_span, place , fake_borrows , candidate, pats) ,
1484
+ skip( self , start_block, otherwise_block, or_span, candidate, pats) ,
1518
1485
level = "debug"
1519
1486
) ]
1520
1487
fn test_or_pattern < ' pat > (
1521
1488
& mut self ,
1522
1489
candidate : & mut Candidate < ' pat , ' tcx > ,
1523
1490
start_block : BasicBlock ,
1524
1491
otherwise_block : BasicBlock ,
1525
- pats : & ' pat [ Box < Pat < ' tcx > > ] ,
1492
+ pats : & [ FlatPat < ' pat , ' tcx > ] ,
1526
1493
or_span : Span ,
1527
- place : & PlaceBuilder < ' tcx > ,
1528
- fake_borrows : & mut Option < FxIndexSet < Place < ' tcx > > > ,
1529
1494
) {
1530
1495
debug ! ( "candidate={:#?}\n pats={:#?}" , candidate, pats) ;
1531
1496
let mut or_candidates: Vec < _ > = pats
1532
1497
. iter ( )
1533
- . map ( |pat| Candidate :: new ( place. clone ( ) , pat, candidate. has_guard , self ) )
1498
+ . cloned ( )
1499
+ . map ( |flat_pat| Candidate :: from_flat_pat ( flat_pat, candidate. has_guard ) )
1534
1500
. collect ( ) ;
1535
1501
let mut or_candidate_refs: Vec < _ > = or_candidates. iter_mut ( ) . collect ( ) ;
1536
1502
self . match_candidates (
@@ -1539,7 +1505,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1539
1505
start_block,
1540
1506
otherwise_block,
1541
1507
& mut or_candidate_refs,
1542
- fake_borrows,
1543
1508
) ;
1544
1509
candidate. subcandidates = or_candidates;
1545
1510
self . merge_trivial_subcandidates ( candidate, self . source_info ( or_span) ) ;
@@ -1599,7 +1564,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1599
1564
fn pick_test (
1600
1565
& mut self ,
1601
1566
candidates : & mut [ & mut Candidate < ' _ , ' tcx > ] ,
1602
- fake_borrows : & mut Option < FxIndexSet < Place < ' tcx > > > ,
1603
1567
) -> ( PlaceBuilder < ' tcx > , Test < ' tcx > ) {
1604
1568
// Extract the match-pair from the highest priority candidate
1605
1569
let match_pair = & candidates. first ( ) . unwrap ( ) . match_pairs [ 0 ] ;
@@ -1628,13 +1592,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1628
1592
_ => { }
1629
1593
}
1630
1594
1631
- // Insert a Shallow borrow of any places that is switched on.
1632
- if let Some ( fb) = fake_borrows
1633
- && let Some ( resolved_place) = match_place. try_to_place ( self )
1634
- {
1635
- fb. insert ( resolved_place) ;
1636
- }
1637
-
1638
1595
( match_place, test)
1639
1596
}
1640
1597
@@ -1808,10 +1765,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1808
1765
candidates : & ' b mut [ & ' c mut Candidate < ' pat , ' tcx > ] ,
1809
1766
start_block : BasicBlock ,
1810
1767
otherwise_block : BasicBlock ,
1811
- fake_borrows : & mut Option < FxIndexSet < Place < ' tcx > > > ,
1812
1768
) {
1813
1769
// Extract the match-pair from the highest priority candidate and build a test from it.
1814
- let ( match_place, test) = self . pick_test ( candidates, fake_borrows ) ;
1770
+ let ( match_place, test) = self . pick_test ( candidates) ;
1815
1771
1816
1772
// For each of the N possible test outcomes, build the vector of candidates that applies if
1817
1773
// the test has that particular outcome.
@@ -1828,7 +1784,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1828
1784
remainder_start,
1829
1785
otherwise_block,
1830
1786
remaining_candidates,
1831
- fake_borrows,
1832
1787
) ;
1833
1788
remainder_start
1834
1789
} else {
@@ -1850,7 +1805,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1850
1805
candidate_start,
1851
1806
remainder_start,
1852
1807
& mut * candidates,
1853
- fake_borrows,
1854
1808
) ;
1855
1809
candidate_start
1856
1810
} else {
0 commit comments