@@ -1364,61 +1364,105 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
13641364 otherwise_block : BasicBlock ,
13651365 candidates : & mut [ & mut Candidate < ' pat , ' tcx > ] ,
13661366 ) {
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) ;
13701402
13711403 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 { .. } , .. } , ..] =
13851418 & * candidate. match_pairs
13861419 {
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.
13891424 for subcandidate in candidate. subcandidates . iter_mut ( ) {
1390- new_candidates . push ( subcandidate) ;
1425+ expanded_candidates . push ( subcandidate) ;
13911426 }
13921427 } else {
1393- new_candidates . push ( candidate) ;
1428+ expanded_candidates . push ( candidate) ;
13941429 }
13951430 }
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.
13961436 self . match_candidates (
13971437 span,
13981438 scrutinee_span,
13991439 start_block,
1400- otherwise_block ,
1401- new_candidates . as_mut_slice ( ) ,
1440+ remainder_start ,
1441+ expanded_candidates . as_mut_slice ( ) ,
14021442 ) ;
14031443
1404- for candidate in candidates {
1444+ // Simplify subcandidates and process any leftover match pairs.
1445+ for candidate in candidates_to_expand {
14051446 if !candidate. subcandidates . is_empty ( ) {
1406- self . merge_trivial_subcandidates ( candidate) ;
1447+ self . finalize_or_candidate ( span , scrutinee_span , candidate) ;
14071448 }
14081449 }
1409- } else {
1410- self . match_simplified_candidates (
1450+
1451+ // Process the remaining candidates.
1452+ self . match_candidates (
14111453 span,
14121454 scrutinee_span,
1413- start_block ,
1455+ remainder_start ,
14141456 otherwise_block,
1415- candidates ,
1457+ remaining_candidates ,
14161458 ) ;
14171459 }
14181460 } ) ;
14191461 }
14201462
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 (
14221466 & mut self ,
14231467 span : Span ,
14241468 scrutinee_span : Span ,
@@ -1443,7 +1487,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
14431487 // The first candidate has satisfied all its match pairs; we link it up and continue
14441488 // with the remaining candidates.
14451489 start_block = self . select_matched_candidate ( first, start_block) ;
1446- self . match_simplified_candidates (
1490+ self . match_expanded_candidates (
14471491 span,
14481492 scrutinee_span,
14491493 start_block,
@@ -1453,7 +1497,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
14531497 }
14541498 candidates => {
14551499 // The first candidate has some unsatisfied match pairs; we proceed to do more tests.
1456- self . test_candidates_with_or (
1500+ self . test_candidates (
14571501 span,
14581502 scrutinee_span,
14591503 candidates,
@@ -1506,8 +1550,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
15061550 otherwise_block
15071551 }
15081552
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` .
15111555 ///
15121556 /// Given a pattern `(P | Q, R | S)` we (in principle) generate a CFG like
15131557 /// so:
@@ -1559,45 +1603,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
15591603 /// |
15601604 /// ...
15611605 /// ```
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`.
16011606 fn finalize_or_candidate (
16021607 & mut self ,
16031608 span : Span ,
@@ -1634,40 +1639,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
16341639 } else {
16351640 last_otherwise. unwrap ( )
16361641 } ;
1637- self . test_candidates_with_or (
1642+ self . match_candidates (
16381643 span,
16391644 scrutinee_span,
1640- & mut [ leaf_candidate] ,
16411645 or_start,
16421646 or_otherwise,
1647+ & mut [ leaf_candidate] ,
16431648 ) ;
16441649 } ) ;
16451650 }
16461651 }
16471652
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-
16711653 /// Given a match-pair that corresponds to an or-pattern, expand each subpattern into a new
16721654 /// subcandidate. Any candidate that has been expanded that way should be passed to
16731655 /// `finalize_or_candidate` after its subcandidates have been processed.
0 commit comments