@@ -1364,61 +1364,105 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1364
1364
otherwise_block : BasicBlock ,
1365
1365
candidates : & mut [ & mut Candidate < ' pat , ' tcx > ] ,
1366
1366
) {
1367
- let expand_or_pats = candidates. iter ( ) . any ( |candidate| {
1368
- matches ! ( & * candidate. match_pairs, [ MatchPair { test_case: TestCase :: Or { .. } , .. } ] )
1369
- } ) ;
1367
+ // We process or-patterns here. If any candidate starts with an or-pattern, we have to
1368
+ // expand the or-pattern before we can proceed further.
1369
+ //
1370
+ // We can't expand them freely however. The rule is: if the candidate has an or-pattern as
1371
+ // its only remaining match pair, we can expand it freely. If it has other match pairs, we
1372
+ // can expand it but we can't process more candidates after it.
1373
+ //
1374
+ // If we didn't stop, the `otherwise` cases could get mixed up. E.g. in the following,
1375
+ // or-pattern simplification (in `merge_trivial_subcandidates`) makes it so the `1` and `2`
1376
+ // cases branch to a same block (which then tests `false`). If we took `(2, _)` in the same
1377
+ // set of candidates, when we reach the block that tests `false` we don't know whether we
1378
+ // came from `1` or `2`, hence we can't know where to branch on failure.
1379
+ // ```ignore(illustrative)
1380
+ // match (1, true) {
1381
+ // (1 | 2, false) => {},
1382
+ // (2, _) => {},
1383
+ // _ => {}
1384
+ // }
1385
+ // ```
1386
+ //
1387
+ // We therefore split the `candidates` slice in two, expand or-patterns in the first half,
1388
+ // and process both halves separately.
1389
+ let mut expand_until = 0 ;
1390
+ for ( i, candidate) in candidates. iter ( ) . enumerate ( ) {
1391
+ if matches ! (
1392
+ & * candidate. match_pairs,
1393
+ [ MatchPair { test_case: TestCase :: Or { .. } , .. } , ..]
1394
+ ) {
1395
+ expand_until = i + 1 ;
1396
+ if candidate. match_pairs . len ( ) > 1 {
1397
+ break ;
1398
+ }
1399
+ }
1400
+ }
1401
+ let ( candidates_to_expand, remaining_candidates) = candidates. split_at_mut ( expand_until) ;
1370
1402
1371
1403
ensure_sufficient_stack ( || {
1372
- if expand_or_pats {
1373
- // Split a candidate in which the only match-pair is an or-pattern into multiple
1374
- // candidates. This is so that
1375
- //
1376
- // match x {
1377
- // 0 | 1 => { ... },
1378
- // 2 | 3 => { ... },
1379
- // }
1380
- //
1381
- // only generates a single switch.
1382
- let mut new_candidates = Vec :: new ( ) ;
1383
- for candidate in candidates. iter_mut ( ) {
1384
- if let [ MatchPair { test_case : TestCase :: Or { .. } , .. } ] =
1404
+ if candidates_to_expand. is_empty ( ) {
1405
+ // No candidates start with an or-pattern, we can continue.
1406
+ self . match_expanded_candidates (
1407
+ span,
1408
+ scrutinee_span,
1409
+ start_block,
1410
+ otherwise_block,
1411
+ remaining_candidates,
1412
+ ) ;
1413
+ } else {
1414
+ // Expand one level of or-patterns for each candidate in `candidates_to_expand`.
1415
+ let mut expanded_candidates = Vec :: new ( ) ;
1416
+ for candidate in candidates_to_expand. iter_mut ( ) {
1417
+ if let [ MatchPair { test_case : TestCase :: Or { .. } , .. } , ..] =
1385
1418
& * candidate. match_pairs
1386
1419
{
1387
- let match_pair = candidate. match_pairs . pop ( ) . unwrap ( ) ;
1388
- self . create_or_subcandidates ( candidate, match_pair) ;
1420
+ let or_match_pair = candidate. match_pairs . remove ( 0 ) ;
1421
+ // Expand the or-pattern into subcandidates.
1422
+ self . create_or_subcandidates ( candidate, or_match_pair) ;
1423
+ // Collect the newly created subcandidates.
1389
1424
for subcandidate in candidate. subcandidates . iter_mut ( ) {
1390
- new_candidates . push ( subcandidate) ;
1425
+ expanded_candidates . push ( subcandidate) ;
1391
1426
}
1392
1427
} else {
1393
- new_candidates . push ( candidate) ;
1428
+ expanded_candidates . push ( candidate) ;
1394
1429
}
1395
1430
}
1431
+
1432
+ // Process the expanded candidates.
1433
+ let remainder_start = self . cfg . start_new_block ( ) ;
1434
+ // There might be new or-patterns obtained from expanding the old ones, so we call
1435
+ // `match_candidates` again.
1396
1436
self . match_candidates (
1397
1437
span,
1398
1438
scrutinee_span,
1399
1439
start_block,
1400
- otherwise_block ,
1401
- new_candidates . as_mut_slice ( ) ,
1440
+ remainder_start ,
1441
+ expanded_candidates . as_mut_slice ( ) ,
1402
1442
) ;
1403
1443
1404
- for candidate in candidates {
1444
+ // Simplify subcandidates and process any leftover match pairs.
1445
+ for candidate in candidates_to_expand {
1405
1446
if !candidate. subcandidates . is_empty ( ) {
1406
- self . merge_trivial_subcandidates ( candidate) ;
1447
+ self . finalize_or_candidate ( span , scrutinee_span , candidate) ;
1407
1448
}
1408
1449
}
1409
- } else {
1410
- self . match_simplified_candidates (
1450
+
1451
+ // Process the remaining candidates.
1452
+ self . match_candidates (
1411
1453
span,
1412
1454
scrutinee_span,
1413
- start_block ,
1455
+ remainder_start ,
1414
1456
otherwise_block,
1415
- candidates ,
1457
+ remaining_candidates ,
1416
1458
) ;
1417
1459
}
1418
1460
} ) ;
1419
1461
}
1420
1462
1421
- fn match_simplified_candidates (
1463
+ /// Construct the decision tree for `candidates`. Caller must ensure that no candidate in
1464
+ /// `candidates` starts with an or-pattern.
1465
+ fn match_expanded_candidates (
1422
1466
& mut self ,
1423
1467
span : Span ,
1424
1468
scrutinee_span : Span ,
@@ -1443,7 +1487,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1443
1487
// The first candidate has satisfied all its match pairs; we link it up and continue
1444
1488
// with the remaining candidates.
1445
1489
start_block = self . select_matched_candidate ( first, start_block) ;
1446
- self . match_simplified_candidates (
1490
+ self . match_expanded_candidates (
1447
1491
span,
1448
1492
scrutinee_span,
1449
1493
start_block,
@@ -1453,7 +1497,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1453
1497
}
1454
1498
candidates => {
1455
1499
// The first candidate has some unsatisfied match pairs; we proceed to do more tests.
1456
- self . test_candidates_with_or (
1500
+ self . test_candidates (
1457
1501
span,
1458
1502
scrutinee_span,
1459
1503
candidates,
@@ -1506,8 +1550,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1506
1550
otherwise_block
1507
1551
}
1508
1552
1509
- /// Tests a candidate where there are only or-patterns left to test, or
1510
- /// forwards to [Builder::test_candidates] .
1553
+ /// Simplify subcandidates and process any leftover match pairs. The candidate should have been
1554
+ /// expanded with `create_or_subcandidates` .
1511
1555
///
1512
1556
/// Given a pattern `(P | Q, R | S)` we (in principle) generate a CFG like
1513
1557
/// so:
@@ -1559,45 +1603,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1559
1603
/// |
1560
1604
/// ...
1561
1605
/// ```
1562
- fn test_candidates_with_or (
1563
- & mut self ,
1564
- span : Span ,
1565
- scrutinee_span : Span ,
1566
- candidates : & mut [ & mut Candidate < ' _ , ' tcx > ] ,
1567
- start_block : BasicBlock ,
1568
- otherwise_block : BasicBlock ,
1569
- ) {
1570
- let ( first_candidate, remaining_candidates) = candidates. split_first_mut ( ) . unwrap ( ) ;
1571
- assert ! ( first_candidate. subcandidates. is_empty( ) ) ;
1572
- if !matches ! ( first_candidate. match_pairs[ 0 ] . test_case, TestCase :: Or { .. } ) {
1573
- self . test_candidates ( span, scrutinee_span, candidates, start_block, otherwise_block) ;
1574
- return ;
1575
- }
1576
-
1577
- let first_match_pair = first_candidate. match_pairs . remove ( 0 ) ;
1578
- let remainder_start = self . cfg . start_new_block ( ) ;
1579
- // Test the alternatives of this or-pattern.
1580
- self . test_or_pattern (
1581
- span,
1582
- scrutinee_span,
1583
- first_candidate,
1584
- start_block,
1585
- remainder_start,
1586
- first_match_pair,
1587
- ) ;
1588
-
1589
- // Test the remaining candidates.
1590
- self . match_candidates (
1591
- span,
1592
- scrutinee_span,
1593
- remainder_start,
1594
- otherwise_block,
1595
- remaining_candidates,
1596
- ) ;
1597
- }
1598
-
1599
- /// Simplify subcandidates and process any leftover match pairs. The candidate should have been
1600
- /// expanded with `create_or_subcandidates`.
1601
1606
fn finalize_or_candidate (
1602
1607
& mut self ,
1603
1608
span : Span ,
@@ -1634,40 +1639,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1634
1639
} else {
1635
1640
last_otherwise. unwrap ( )
1636
1641
} ;
1637
- self . test_candidates_with_or (
1642
+ self . match_candidates (
1638
1643
span,
1639
1644
scrutinee_span,
1640
- & mut [ leaf_candidate] ,
1641
1645
or_start,
1642
1646
or_otherwise,
1647
+ & mut [ leaf_candidate] ,
1643
1648
) ;
1644
1649
} ) ;
1645
1650
}
1646
1651
}
1647
1652
1648
- #[ instrument( skip( self , start_block, otherwise_block, candidate, match_pair) , level = "debug" ) ]
1649
- fn test_or_pattern < ' pat > (
1650
- & mut self ,
1651
- span : Span ,
1652
- scrutinee_span : Span ,
1653
- candidate : & mut Candidate < ' pat , ' tcx > ,
1654
- start_block : BasicBlock ,
1655
- otherwise_block : BasicBlock ,
1656
- match_pair : MatchPair < ' pat , ' tcx > ,
1657
- ) {
1658
- let or_span = match_pair. pattern . span ;
1659
- self . create_or_subcandidates ( candidate, match_pair) ;
1660
- let mut or_candidate_refs: Vec < _ > = candidate. subcandidates . iter_mut ( ) . collect ( ) ;
1661
- self . match_candidates (
1662
- or_span,
1663
- or_span,
1664
- start_block,
1665
- otherwise_block,
1666
- & mut or_candidate_refs,
1667
- ) ;
1668
- self . finalize_or_candidate ( span, scrutinee_span, candidate) ;
1669
- }
1670
-
1671
1653
/// Given a match-pair that corresponds to an or-pattern, expand each subpattern into a new
1672
1654
/// subcandidate. Any candidate that has been expanded that way should be passed to
1673
1655
/// `finalize_or_candidate` after its subcandidates have been processed.
0 commit comments