@@ -1427,108 +1427,39 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1427
1427
/// Note how we test `x` twice. This is the tradeoff of backtracking automata: we prefer smaller
1428
1428
/// code size at the expense of non-optimal code paths.
1429
1429
#[ instrument( skip( self ) , level = "debug" ) ]
1430
- fn match_candidates < ' pat > (
1430
+ fn match_candidates (
1431
1431
& mut self ,
1432
1432
span : Span ,
1433
1433
scrutinee_span : Span ,
1434
1434
start_block : BasicBlock ,
1435
1435
otherwise_block : BasicBlock ,
1436
- candidates : & mut [ & mut Candidate < ' pat , ' tcx > ] ,
1436
+ candidates : & mut [ & mut Candidate < ' _ , ' tcx > ] ,
1437
1437
) {
1438
- // We process or-patterns here. If any candidate starts with an or-pattern, we have to
1439
- // expand the or-pattern before we can proceed further.
1440
- //
1441
- // We can't expand them freely however. The rule is: if the candidate has an or-pattern as
1442
- // its only remaining match pair, we can expand it freely. If it has other match pairs, we
1443
- // can expand it but we can't process more candidates after it.
1444
- //
1445
- // If we didn't stop, the `otherwise` cases could get mixed up. E.g. in the following,
1446
- // or-pattern simplification (in `merge_trivial_subcandidates`) makes it so the `1` and `2`
1447
- // cases branch to a same block (which then tests `false`). If we took `(2, _)` in the same
1448
- // set of candidates, when we reach the block that tests `false` we don't know whether we
1449
- // came from `1` or `2`, hence we can't know where to branch on failure.
1450
- // ```ignore(illustrative)
1451
- // match (1, true) {
1452
- // (1 | 2, false) => {},
1453
- // (2, _) => {},
1454
- // _ => {}
1455
- // }
1456
- // ```
1457
- //
1458
- // We therefore split the `candidates` slice in two, expand or-patterns in the first half,
1459
- // and process both halves separately.
1460
- let mut expand_until = 0 ;
1461
- for ( i, candidate) in candidates. iter ( ) . enumerate ( ) {
1462
- if matches ! (
1438
+ // If any candidate starts with an or-pattern, we have to expand the or-pattern before we
1439
+ // can proceed further.
1440
+ let expand_ors = candidates. iter ( ) . any ( |candidate| {
1441
+ matches ! (
1463
1442
& * candidate. match_pairs,
1464
1443
[ MatchPair { test_case: TestCase :: Or { .. } , .. } , ..]
1465
- ) {
1466
- expand_until = i + 1 ;
1467
- if candidate. match_pairs . len ( ) > 1 {
1468
- break ;
1469
- }
1470
- }
1471
- if expand_until != 0 {
1472
- expand_until = i + 1 ;
1473
- }
1474
- }
1475
- let ( candidates_to_expand, remaining_candidates) = candidates. split_at_mut ( expand_until) ;
1476
-
1444
+ )
1445
+ } ) ;
1477
1446
ensure_sufficient_stack ( || {
1478
- if candidates_to_expand . is_empty ( ) {
1447
+ if !expand_ors {
1479
1448
// No candidates start with an or-pattern, we can continue.
1480
1449
self . match_expanded_candidates (
1481
1450
span,
1482
1451
scrutinee_span,
1483
1452
start_block,
1484
1453
otherwise_block,
1485
- remaining_candidates ,
1454
+ candidates ,
1486
1455
) ;
1487
1456
} else {
1488
- // Expand one level of or-patterns for each candidate in `candidates_to_expand`.
1489
- let mut expanded_candidates = Vec :: new ( ) ;
1490
- for candidate in candidates_to_expand. iter_mut ( ) {
1491
- if let [ MatchPair { test_case : TestCase :: Or { .. } , .. } , ..] =
1492
- & * candidate. match_pairs
1493
- {
1494
- let or_match_pair = candidate. match_pairs . remove ( 0 ) ;
1495
- // Expand the or-pattern into subcandidates.
1496
- self . create_or_subcandidates ( candidate, or_match_pair) ;
1497
- // Collect the newly created subcandidates.
1498
- for subcandidate in candidate. subcandidates . iter_mut ( ) {
1499
- expanded_candidates. push ( subcandidate) ;
1500
- }
1501
- } else {
1502
- expanded_candidates. push ( candidate) ;
1503
- }
1504
- }
1505
-
1506
- // Process the expanded candidates.
1507
- let remainder_start = self . cfg . start_new_block ( ) ;
1508
- // There might be new or-patterns obtained from expanding the old ones, so we call
1509
- // `match_candidates` again.
1510
- self . match_candidates (
1457
+ self . expand_and_match_or_candidates (
1511
1458
span,
1512
1459
scrutinee_span,
1513
1460
start_block,
1514
- remainder_start,
1515
- expanded_candidates. as_mut_slice ( ) ,
1516
- ) ;
1517
-
1518
- // Simplify subcandidates and process any leftover match pairs.
1519
- for candidate in candidates_to_expand {
1520
- if !candidate. subcandidates . is_empty ( ) {
1521
- self . finalize_or_candidate ( span, scrutinee_span, candidate) ;
1522
- }
1523
- }
1524
-
1525
- // Process the remaining candidates.
1526
- self . match_candidates (
1527
- span,
1528
- scrutinee_span,
1529
- remainder_start,
1530
1461
otherwise_block,
1531
- remaining_candidates ,
1462
+ candidates ,
1532
1463
) ;
1533
1464
}
1534
1465
} ) ;
@@ -1624,6 +1555,98 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1624
1555
otherwise_block
1625
1556
}
1626
1557
1558
+ /// Takes a list of candidates such that some of the candidates' first match pairs are
1559
+ /// or-patterns, expands as many or-patterns as possible, and processes the resulting
1560
+ /// candidates.
1561
+ fn expand_and_match_or_candidates (
1562
+ & mut self ,
1563
+ span : Span ,
1564
+ scrutinee_span : Span ,
1565
+ start_block : BasicBlock ,
1566
+ otherwise_block : BasicBlock ,
1567
+ candidates : & mut [ & mut Candidate < ' _ , ' tcx > ] ,
1568
+ ) {
1569
+ // We can't expand or-patterns freely. The rule is: if the candidate has an
1570
+ // or-pattern as its only remaining match pair, we can expand it freely. If it has
1571
+ // other match pairs, we can expand it but we can't process more candidates after
1572
+ // it.
1573
+ //
1574
+ // If we didn't stop, the `otherwise` cases could get mixed up. E.g. in the
1575
+ // following, or-pattern simplification (in `merge_trivial_subcandidates`) makes it
1576
+ // so the `1` and `2` cases branch to a same block (which then tests `false`). If we
1577
+ // took `(2, _)` in the same set of candidates, when we reach the block that tests
1578
+ // `false` we don't know whether we came from `1` or `2`, hence we can't know where
1579
+ // to branch on failure.
1580
+ //
1581
+ // ```ignore(illustrative)
1582
+ // match (1, true) {
1583
+ // (1 | 2, false) => {},
1584
+ // (2, _) => {},
1585
+ // _ => {}
1586
+ // }
1587
+ // ```
1588
+ //
1589
+ // We therefore split the `candidates` slice in two, expand or-patterns in the first half,
1590
+ // and process the rest separately.
1591
+ let mut expand_until = 0 ;
1592
+ for ( i, candidate) in candidates. iter ( ) . enumerate ( ) {
1593
+ expand_until = i + 1 ;
1594
+ if candidate. match_pairs . len ( ) > 1
1595
+ && matches ! ( & candidate. match_pairs[ 0 ] . test_case, TestCase :: Or { .. } )
1596
+ {
1597
+ // The candidate has an or-pattern as well as more match pairs: we must
1598
+ // split the candidates list here.
1599
+ break ;
1600
+ }
1601
+ }
1602
+ let ( candidates_to_expand, remaining_candidates) = candidates. split_at_mut ( expand_until) ;
1603
+
1604
+ // Expand one level of or-patterns for each candidate in `candidates_to_expand`.
1605
+ let mut expanded_candidates = Vec :: new ( ) ;
1606
+ for candidate in candidates_to_expand. iter_mut ( ) {
1607
+ if let [ MatchPair { test_case : TestCase :: Or { .. } , .. } , ..] = & * candidate. match_pairs
1608
+ {
1609
+ let or_match_pair = candidate. match_pairs . remove ( 0 ) ;
1610
+ // Expand the or-pattern into subcandidates.
1611
+ self . create_or_subcandidates ( candidate, or_match_pair) ;
1612
+ // Collect the newly created subcandidates.
1613
+ for subcandidate in candidate. subcandidates . iter_mut ( ) {
1614
+ expanded_candidates. push ( subcandidate) ;
1615
+ }
1616
+ } else {
1617
+ expanded_candidates. push ( candidate) ;
1618
+ }
1619
+ }
1620
+
1621
+ // Process the expanded candidates.
1622
+ let remainder_start = self . cfg . start_new_block ( ) ;
1623
+ // There might be new or-patterns obtained from expanding the old ones, so we call
1624
+ // `match_candidates` again.
1625
+ self . match_candidates (
1626
+ span,
1627
+ scrutinee_span,
1628
+ start_block,
1629
+ remainder_start,
1630
+ expanded_candidates. as_mut_slice ( ) ,
1631
+ ) ;
1632
+
1633
+ // Simplify subcandidates and process any leftover match pairs.
1634
+ for candidate in candidates_to_expand {
1635
+ if !candidate. subcandidates . is_empty ( ) {
1636
+ self . finalize_or_candidate ( span, scrutinee_span, candidate) ;
1637
+ }
1638
+ }
1639
+
1640
+ // Process the remaining candidates.
1641
+ self . match_candidates (
1642
+ span,
1643
+ scrutinee_span,
1644
+ remainder_start,
1645
+ otherwise_block,
1646
+ remaining_candidates,
1647
+ ) ;
1648
+ }
1649
+
1627
1650
/// Given a match-pair that corresponds to an or-pattern, expand each subpattern into a new
1628
1651
/// subcandidate. Any candidate that has been expanded that way should be passed to
1629
1652
/// `finalize_or_candidate` after its subcandidates have been processed.
0 commit comments