@@ -1427,108 +1427,39 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
14271427 /// Note how we test `x` twice. This is the tradeoff of backtracking automata: we prefer smaller
14281428 /// code size at the expense of non-optimal code paths.
14291429 #[ instrument( skip( self ) , level = "debug" ) ]
1430- fn match_candidates < ' pat > (
1430+ fn match_candidates (
14311431 & mut self ,
14321432 span : Span ,
14331433 scrutinee_span : Span ,
14341434 start_block : BasicBlock ,
14351435 otherwise_block : BasicBlock ,
1436- candidates : & mut [ & mut Candidate < ' pat , ' tcx > ] ,
1436+ candidates : & mut [ & mut Candidate < ' _ , ' tcx > ] ,
14371437 ) {
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 ! (
14631442 & * candidate. match_pairs,
14641443 [ 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+ } ) ;
14771446 ensure_sufficient_stack ( || {
1478- if candidates_to_expand . is_empty ( ) {
1447+ if !expand_ors {
14791448 // No candidates start with an or-pattern, we can continue.
14801449 self . match_expanded_candidates (
14811450 span,
14821451 scrutinee_span,
14831452 start_block,
14841453 otherwise_block,
1485- remaining_candidates ,
1454+ candidates ,
14861455 ) ;
14871456 } 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 (
15111458 span,
15121459 scrutinee_span,
15131460 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,
15301461 otherwise_block,
1531- remaining_candidates ,
1462+ candidates ,
15321463 ) ;
15331464 }
15341465 } ) ;
@@ -1624,6 +1555,98 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
16241555 otherwise_block
16251556 }
16261557
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+
16271650 /// Given a match-pair that corresponds to an or-pattern, expand each subpattern into a new
16281651 /// subcandidate. Any candidate that has been expanded that way should be passed to
16291652 /// `finalize_or_candidate` after its subcandidates have been processed.
0 commit comments