@@ -321,20 +321,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
321
321
// The set of places that we are creating fake borrows of. If there are
322
322
// no match guards then we don't need any fake borrows, so don't track
323
323
// 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) ) ;
325
326
326
327
let otherwise_block = self . cfg . start_new_block ( ) ;
327
328
328
329
// This will generate code to test scrutinee_place and
329
330
// 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) ;
338
332
339
333
// See the doc comment on `match_candidates` for why we may have an
340
334
// otherwise block. Match checking will ensure this is actually
@@ -944,6 +938,40 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
944
938
}
945
939
}
946
940
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
+
947
975
#[ derive( Debug ) ]
948
976
struct Candidate < ' pat , ' tcx > {
949
977
/// [`Span`] of the original pattern that gave rise to this candidate.
@@ -958,11 +986,11 @@ struct Candidate<'pat, 'tcx> {
958
986
match_pairs : Vec < MatchPair < ' pat , ' tcx > > ,
959
987
960
988
/// ...these bindings established...
961
- // Invariant: not mutated outside `Candidate::new()` .
989
+ // Invariant: not mutated after candidate creation .
962
990
bindings : Vec < Binding < ' tcx > > ,
963
991
964
992
/// ...and these types asserted...
965
- // Invariant: not mutated outside `Candidate::new()` .
993
+ // Invariant: not mutated after candidate creation .
966
994
ascriptions : Vec < Ascription < ' tcx > > ,
967
995
968
996
/// ...and if this is non-empty, one of these subcandidates also has to match...
@@ -984,25 +1012,21 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
984
1012
has_guard : bool ,
985
1013
cx : & mut Builder < ' _ , ' tcx > ,
986
1014
) -> 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 ,
989
1024
has_guard,
990
- match_pairs : vec ! [ MatchPair :: new( place, pattern, cx) ] ,
991
- bindings : Vec :: new ( ) ,
992
- ascriptions : Vec :: new ( ) ,
993
1025
subcandidates : Vec :: new ( ) ,
994
1026
otherwise_block : None ,
995
1027
pre_binding_block : None ,
996
1028
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
+ }
1006
1030
}
1007
1031
1008
1032
/// Visit the leaf candidates (those with no subcandidates) contained in
@@ -1065,7 +1089,7 @@ enum TestCase<'pat, 'tcx> {
1065
1089
Constant { value : mir:: Const < ' tcx > } ,
1066
1090
Range ( & ' pat PatRange < ' tcx > ) ,
1067
1091
Slice { len : usize , variable_length : bool } ,
1068
- Or ,
1092
+ Or { pats : Box < [ FlatPat < ' pat , ' tcx > ] > } ,
1069
1093
}
1070
1094
1071
1095
#[ derive( Debug , Clone ) ]
@@ -1208,19 +1232,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1208
1232
///
1209
1233
/// Note how we test `x` twice. This is the tradeoff of backtracking automata: we prefer smaller
1210
1234
/// code size at the expense of non-optimal code paths.
1211
- #[ instrument( skip( self , fake_borrows ) , level = "debug" ) ]
1235
+ #[ instrument( skip( self ) , level = "debug" ) ]
1212
1236
fn match_candidates < ' pat > (
1213
1237
& mut self ,
1214
1238
span : Span ,
1215
1239
scrutinee_span : Span ,
1216
1240
start_block : BasicBlock ,
1217
1241
otherwise_block : BasicBlock ,
1218
1242
candidates : & mut [ & mut Candidate < ' pat , ' tcx > ] ,
1219
- fake_borrows : & mut Option < FxIndexSet < Place < ' tcx > > > ,
1220
1243
) {
1221
1244
let mut split_or_candidate = false ;
1222
1245
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, .. } , .. } ] =
1224
1247
& * candidate. match_pairs
1225
1248
{
1226
1249
// 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> {
1232
1255
// }
1233
1256
//
1234
1257
// 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 ) ;
1237
1259
candidate. match_pairs . pop ( ) ;
1238
1260
split_or_candidate = true ;
1239
1261
}
@@ -1254,7 +1276,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1254
1276
start_block,
1255
1277
otherwise_block,
1256
1278
& mut * new_candidates,
1257
- fake_borrows,
1258
1279
) ;
1259
1280
} else {
1260
1281
self . match_simplified_candidates (
@@ -1263,7 +1284,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1263
1284
start_block,
1264
1285
otherwise_block,
1265
1286
candidates,
1266
- fake_borrows,
1267
1287
) ;
1268
1288
}
1269
1289
} ) ;
@@ -1276,7 +1296,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1276
1296
mut start_block : BasicBlock ,
1277
1297
otherwise_block : BasicBlock ,
1278
1298
candidates : & mut [ & mut Candidate < ' _ , ' tcx > ] ,
1279
- fake_borrows : & mut Option < FxIndexSet < Place < ' tcx > > > ,
1280
1299
) {
1281
1300
match candidates {
1282
1301
[ ] => {
@@ -1288,14 +1307,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1288
1307
[ first, remaining @ ..] if first. match_pairs . is_empty ( ) => {
1289
1308
// The first candidate has satisfied all its match pairs; we link it up and continue
1290
1309
// 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) ;
1292
1311
self . match_simplified_candidates (
1293
1312
span,
1294
1313
scrutinee_span,
1295
1314
start_block,
1296
1315
otherwise_block,
1297
1316
remaining,
1298
- fake_borrows,
1299
1317
)
1300
1318
}
1301
1319
candidates => {
@@ -1306,7 +1324,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1306
1324
candidates,
1307
1325
start_block,
1308
1326
otherwise_block,
1309
- fake_borrows,
1310
1327
) ;
1311
1328
}
1312
1329
}
@@ -1341,43 +1358,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1341
1358
& mut self ,
1342
1359
candidate : & mut Candidate < ' _ , ' tcx > ,
1343
1360
start_block : BasicBlock ,
1344
- fake_borrows : & mut Option < FxIndexSet < Place < ' tcx > > > ,
1345
1361
) -> BasicBlock {
1346
1362
assert ! ( candidate. otherwise_block. is_none( ) ) ;
1347
1363
assert ! ( candidate. pre_binding_block. is_none( ) ) ;
1348
1364
assert ! ( candidate. subcandidates. is_empty( ) ) ;
1349
1365
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
-
1381
1366
candidate. pre_binding_block = Some ( start_block) ;
1382
1367
let otherwise_block = self . cfg . start_new_block ( ) ;
1383
1368
if candidate. has_guard {
@@ -1448,38 +1433,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1448
1433
candidates : & mut [ & mut Candidate < ' _ , ' tcx > ] ,
1449
1434
start_block : BasicBlock ,
1450
1435
otherwise_block : BasicBlock ,
1451
- fake_borrows : & mut Option < FxIndexSet < Place < ' tcx > > > ,
1452
1436
) {
1453
1437
let ( first_candidate, remaining_candidates) = candidates. split_first_mut ( ) . unwrap ( ) ;
1454
1438
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) ;
1464
1441
return ;
1465
1442
}
1466
1443
1467
1444
let match_pairs = mem:: take ( & mut first_candidate. match_pairs ) ;
1468
1445
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 ! ( ) } ;
1470
1447
1471
1448
let remainder_start = self . cfg . start_new_block ( ) ;
1472
1449
let or_span = first_match_pair. pattern . span ;
1473
1450
// 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) ;
1483
1452
1484
1453
if !remaining_match_pairs. is_empty ( ) {
1485
1454
// If more match pairs remain, test them after each subcandidate.
@@ -1500,7 +1469,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1500
1469
& mut [ leaf_candidate] ,
1501
1470
or_start,
1502
1471
or_otherwise,
1503
- fake_borrows,
1504
1472
) ;
1505
1473
} ) ;
1506
1474
}
@@ -1512,28 +1480,26 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1512
1480
remainder_start,
1513
1481
otherwise_block,
1514
1482
remaining_candidates,
1515
- fake_borrows,
1516
1483
) ;
1517
1484
}
1518
1485
1519
1486
#[ 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) ,
1521
1488
level = "debug"
1522
1489
) ]
1523
1490
fn test_or_pattern < ' pat > (
1524
1491
& mut self ,
1525
1492
candidate : & mut Candidate < ' pat , ' tcx > ,
1526
1493
start_block : BasicBlock ,
1527
1494
otherwise_block : BasicBlock ,
1528
- pats : & ' pat [ Box < Pat < ' tcx > > ] ,
1495
+ pats : & [ FlatPat < ' pat , ' tcx > ] ,
1529
1496
or_span : Span ,
1530
- place : & PlaceBuilder < ' tcx > ,
1531
- fake_borrows : & mut Option < FxIndexSet < Place < ' tcx > > > ,
1532
1497
) {
1533
1498
debug ! ( "candidate={:#?}\n pats={:#?}" , candidate, pats) ;
1534
1499
let mut or_candidates: Vec < _ > = pats
1535
1500
. 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 ) )
1537
1503
. collect ( ) ;
1538
1504
let mut or_candidate_refs: Vec < _ > = or_candidates. iter_mut ( ) . collect ( ) ;
1539
1505
self . match_candidates (
@@ -1542,7 +1508,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1542
1508
start_block,
1543
1509
otherwise_block,
1544
1510
& mut or_candidate_refs,
1545
- fake_borrows,
1546
1511
) ;
1547
1512
candidate. subcandidates = or_candidates;
1548
1513
self . merge_trivial_subcandidates ( candidate, self . source_info ( or_span) ) ;
@@ -1602,7 +1567,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1602
1567
fn pick_test (
1603
1568
& mut self ,
1604
1569
candidates : & mut [ & mut Candidate < ' _ , ' tcx > ] ,
1605
- fake_borrows : & mut Option < FxIndexSet < Place < ' tcx > > > ,
1606
1570
) -> ( PlaceBuilder < ' tcx > , Test < ' tcx > ) {
1607
1571
// Extract the match-pair from the highest priority candidate
1608
1572
let match_pair = & candidates. first ( ) . unwrap ( ) . match_pairs [ 0 ] ;
@@ -1631,13 +1595,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1631
1595
_ => { }
1632
1596
}
1633
1597
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
-
1641
1598
( match_place, test)
1642
1599
}
1643
1600
@@ -1811,10 +1768,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1811
1768
candidates : & ' b mut [ & ' c mut Candidate < ' pat , ' tcx > ] ,
1812
1769
start_block : BasicBlock ,
1813
1770
otherwise_block : BasicBlock ,
1814
- fake_borrows : & mut Option < FxIndexSet < Place < ' tcx > > > ,
1815
1771
) {
1816
1772
// 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) ;
1818
1774
1819
1775
// For each of the N possible test outcomes, build the vector of candidates that applies if
1820
1776
// the test has that particular outcome.
@@ -1831,7 +1787,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1831
1787
remainder_start,
1832
1788
otherwise_block,
1833
1789
remaining_candidates,
1834
- fake_borrows,
1835
1790
) ;
1836
1791
remainder_start
1837
1792
} else {
@@ -1853,7 +1808,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1853
1808
candidate_start,
1854
1809
remainder_start,
1855
1810
& mut * candidates,
1856
- fake_borrows,
1857
1811
) ;
1858
1812
candidate_start
1859
1813
} else {
0 commit comments