@@ -1250,11 +1250,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1250
1250
candidates : & mut [ & mut Candidate < ' pat , ' tcx > ] ,
1251
1251
refutable : bool ,
1252
1252
) -> BasicBlock {
1253
+ // This will generate code to test scrutinee_place and branch to the appropriate arm block.
1253
1254
// See the doc comment on `match_candidates` for why we have an otherwise block.
1254
- let otherwise_block = self . cfg . start_new_block ( ) ;
1255
-
1256
- // This will generate code to test scrutinee_place and branch to the appropriate arm block
1257
- self . match_candidates ( match_start_span, scrutinee_span, block, otherwise_block, candidates) ;
1255
+ let otherwise_block =
1256
+ self . match_candidates ( match_start_span, scrutinee_span, block, candidates) ;
1258
1257
1259
1258
// Link each leaf candidate to the `false_edge_start_block` of the next one.
1260
1259
let mut previous_candidate: Option < & mut Candidate < ' _ , ' _ > > = None ;
@@ -1305,27 +1304,24 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1305
1304
otherwise_block
1306
1305
}
1307
1306
1308
- /// The main match algorithm. It begins with a set of candidates
1309
- /// `candidates` and has the job of generating code to determine
1310
- /// which of these candidates, if any, is the correct one . The
1307
+ /// The main match algorithm. It begins with a set of candidates `candidates` and has the job of
1308
+ /// generating code that branches to an appropriate block if the scrutinee matches one of these
1309
+ /// candidates. The
1311
1310
/// candidates are sorted such that the first item in the list
1312
1311
/// has the highest priority. When a candidate is found to match
1313
1312
/// the value, we will set and generate a branch to the appropriate
1314
1313
/// pre-binding block.
1315
1314
///
1316
- /// If we find that *NONE* of the candidates apply, we branch to `otherwise_block`.
1315
+ /// If none of the candidates apply, we continue to the returned `otherwise_block`.
1317
1316
///
1318
1317
/// It might be surprising that the input can be non-exhaustive.
1319
- /// Indeed, initially, it is not, because all matches are
1318
+ /// Indeed, for matches, initially, it is not, because all matches are
1320
1319
/// exhaustive in Rust. But during processing we sometimes divide
1321
1320
/// up the list of candidates and recurse with a non-exhaustive
1322
1321
/// list. This is how our lowering approach (called "backtracking
1323
1322
/// automaton" in the literature) works.
1324
1323
/// See [`Builder::test_candidates`] for more details.
1325
1324
///
1326
- /// If `fake_borrows` is `Some`, then places which need fake borrows
1327
- /// will be added to it.
1328
- ///
1329
1325
/// For an example of how we use `otherwise_block`, consider:
1330
1326
/// ```
1331
1327
/// # fn foo((x, y): (bool, bool)) -> u32 {
@@ -1350,7 +1346,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1350
1346
/// }
1351
1347
/// if y {
1352
1348
/// if x {
1353
- /// // This is actually unreachable because the `(true, true)` case was handled above.
1349
+ /// // This is actually unreachable because the `(true, true)` case was handled above,
1350
+ /// // but we don't know that from within the lowering algorithm.
1354
1351
/// // continue
1355
1352
/// } else {
1356
1353
/// return 3
@@ -1359,33 +1356,26 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1359
1356
/// return 2
1360
1357
/// }
1361
1358
/// // this is the final `otherwise_block`, which is unreachable because the match was exhaustive.
1362
- /// unreachable! ()
1359
+ /// unreachable_unchecked ()
1363
1360
/// # }
1364
1361
/// ```
1365
1362
///
1366
1363
/// Every `continue` is an instance of branching to some `otherwise_block` somewhere deep within
1367
1364
/// the algorithm. For more details on why we lower like this, see [`Builder::test_candidates`].
1368
1365
///
1369
1366
/// Note how we test `x` twice. This is the tradeoff of backtracking automata: we prefer smaller
1370
- /// code size at the expense of non-optimal code paths.
1367
+ /// code size so we accept non-optimal code paths.
1371
1368
#[ instrument( skip( self ) , level = "debug" ) ]
1372
1369
fn match_candidates (
1373
1370
& mut self ,
1374
1371
span : Span ,
1375
1372
scrutinee_span : Span ,
1376
1373
start_block : BasicBlock ,
1377
- otherwise_block : BasicBlock ,
1378
1374
candidates : & mut [ & mut Candidate < ' _ , ' tcx > ] ,
1379
- ) {
1375
+ ) -> BasicBlock {
1380
1376
ensure_sufficient_stack ( || {
1381
- self . match_candidates_with_enough_stack (
1382
- span,
1383
- scrutinee_span,
1384
- start_block,
1385
- otherwise_block,
1386
- candidates,
1387
- )
1388
- } ) ;
1377
+ self . match_candidates_with_enough_stack ( span, scrutinee_span, start_block, candidates)
1378
+ } )
1389
1379
}
1390
1380
1391
1381
/// Construct the decision tree for `candidates`. Don't call this, call `match_candidates`
@@ -1395,9 +1385,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1395
1385
span : Span ,
1396
1386
scrutinee_span : Span ,
1397
1387
start_block : BasicBlock ,
1398
- otherwise_block : BasicBlock ,
1399
1388
candidates : & mut [ & mut Candidate < ' _ , ' tcx > ] ,
1400
- ) {
1389
+ ) -> BasicBlock {
1401
1390
if let [ first, ..] = candidates {
1402
1391
if first. false_edge_start_block . is_none ( ) {
1403
1392
first. false_edge_start_block = Some ( start_block) ;
@@ -1408,9 +1397,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1408
1397
let rest = match candidates {
1409
1398
[ ] => {
1410
1399
// If there are no candidates that still need testing, we're done.
1411
- let source_info = self . source_info ( span) ;
1412
- self . cfg . goto ( start_block, source_info, otherwise_block) ;
1413
- return ;
1400
+ return start_block;
1414
1401
}
1415
1402
[ first, remaining @ ..] if first. match_pairs . is_empty ( ) => {
1416
1403
// The first candidate has satisfied all its match pairs; we link it up and continue
@@ -1431,13 +1418,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1431
1418
1432
1419
// Process any candidates that remain.
1433
1420
let BlockAnd ( start_block, remaining_candidates) = rest;
1434
- self . match_candidates (
1435
- span,
1436
- scrutinee_span,
1437
- start_block,
1438
- otherwise_block,
1439
- remaining_candidates,
1440
- ) ;
1421
+ self . match_candidates ( span, scrutinee_span, start_block, remaining_candidates)
1441
1422
}
1442
1423
1443
1424
/// Link up matched candidates.
@@ -1542,14 +1523,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1542
1523
}
1543
1524
1544
1525
// Process the expanded candidates.
1545
- let remainder_start = self . cfg . start_new_block ( ) ;
1546
- // There might be new or-patterns obtained from expanding the old ones, so we call
1547
- // `match_candidates` again.
1548
- self . match_candidates (
1526
+ let remainder_start = self . match_candidates (
1549
1527
span,
1550
1528
scrutinee_span,
1551
1529
start_block,
1552
- remainder_start,
1553
1530
expanded_candidates. as_mut_slice ( ) ,
1554
1531
) ;
1555
1532
@@ -1648,6 +1625,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1648
1625
self . merge_trivial_subcandidates ( candidate) ;
1649
1626
1650
1627
if !candidate. match_pairs . is_empty ( ) {
1628
+ let or_span = candidate. or_span . unwrap_or ( candidate. extra_data . span ) ;
1629
+ let source_info = self . source_info ( or_span) ;
1651
1630
// If more match pairs remain, test them after each subcandidate.
1652
1631
// We could add them to the or-candidates before the call to `test_or_pattern` but this
1653
1632
// would make it impossible to detect simplifiable or-patterns. That would guarantee
@@ -1661,6 +1640,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1661
1640
assert ! ( leaf_candidate. match_pairs. is_empty( ) ) ;
1662
1641
leaf_candidate. match_pairs . extend ( remaining_match_pairs. iter ( ) . cloned ( ) ) ;
1663
1642
let or_start = leaf_candidate. pre_binding_block . unwrap ( ) ;
1643
+ let otherwise =
1644
+ self . match_candidates ( span, scrutinee_span, or_start, & mut [ leaf_candidate] ) ;
1664
1645
// In a case like `(P | Q, R | S)`, if `P` succeeds and `R | S` fails, we know `(Q,
1665
1646
// R | S)` will fail too. If there is no guard, we skip testing of `Q` by branching
1666
1647
// directly to `last_otherwise`. If there is a guard,
@@ -1671,13 +1652,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1671
1652
} else {
1672
1653
last_otherwise. unwrap ( )
1673
1654
} ;
1674
- self . match_candidates (
1675
- span,
1676
- scrutinee_span,
1677
- or_start,
1678
- or_otherwise,
1679
- & mut [ leaf_candidate] ,
1680
- ) ;
1655
+ self . cfg . goto ( otherwise, source_info, or_otherwise) ;
1681
1656
} ) ;
1682
1657
}
1683
1658
}
@@ -1956,15 +1931,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1956
1931
let target_blocks: FxIndexMap < _ , _ > = target_candidates
1957
1932
. into_iter ( )
1958
1933
. map ( |( branch, mut candidates) | {
1959
- let candidate_start = self . cfg . start_new_block ( ) ;
1960
- self . match_candidates (
1961
- span,
1962
- scrutinee_span,
1963
- candidate_start,
1964
- remainder_start,
1965
- & mut * candidates,
1966
- ) ;
1967
- ( branch, candidate_start)
1934
+ let branch_start = self . cfg . start_new_block ( ) ;
1935
+ let branch_otherwise =
1936
+ self . match_candidates ( span, scrutinee_span, branch_start, & mut * candidates) ;
1937
+ let source_info = self . source_info ( span) ;
1938
+ self . cfg . goto ( branch_otherwise, source_info, remainder_start) ;
1939
+ ( branch, branch_start)
1968
1940
} )
1969
1941
. collect ( ) ;
1970
1942
0 commit comments