@@ -1364,108 +1364,39 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
13641364 /// Note how we test `x` twice. This is the tradeoff of backtracking automata: we prefer smaller
13651365 /// code size at the expense of non-optimal code paths.
13661366 #[ instrument( skip( self ) , level = "debug" ) ]
1367- fn match_candidates < ' pat > (
1367+ fn match_candidates (
13681368 & mut self ,
13691369 span : Span ,
13701370 scrutinee_span : Span ,
13711371 start_block : BasicBlock ,
13721372 otherwise_block : BasicBlock ,
1373- candidates : & mut [ & mut Candidate < ' pat , ' tcx > ] ,
1373+ candidates : & mut [ & mut Candidate < ' _ , ' tcx > ] ,
13741374 ) {
1375- // We process or-patterns here. If any candidate starts with an or-pattern, we have to
1376- // expand the or-pattern before we can proceed further.
1377- //
1378- // We can't expand them freely however. The rule is: if the candidate has an or-pattern as
1379- // its only remaining match pair, we can expand it freely. If it has other match pairs, we
1380- // can expand it but we can't process more candidates after it.
1381- //
1382- // If we didn't stop, the `otherwise` cases could get mixed up. E.g. in the following,
1383- // or-pattern simplification (in `merge_trivial_subcandidates`) makes it so the `1` and `2`
1384- // cases branch to a same block (which then tests `false`). If we took `(2, _)` in the same
1385- // set of candidates, when we reach the block that tests `false` we don't know whether we
1386- // came from `1` or `2`, hence we can't know where to branch on failure.
1387- // ```ignore(illustrative)
1388- // match (1, true) {
1389- // (1 | 2, false) => {},
1390- // (2, _) => {},
1391- // _ => {}
1392- // }
1393- // ```
1394- //
1395- // We therefore split the `candidates` slice in two, expand or-patterns in the first half,
1396- // and process both halves separately.
1397- let mut expand_until = 0 ;
1398- for ( i, candidate) in candidates. iter ( ) . enumerate ( ) {
1399- if matches ! (
1375+ // If any candidate starts with an or-pattern, we have to expand the or-pattern before we
1376+ // can proceed further.
1377+ let expand_ors = candidates. iter ( ) . any ( |candidate| {
1378+ matches ! (
14001379 & * candidate. match_pairs,
14011380 [ MatchPair { test_case: TestCase :: Or { .. } , .. } , ..]
1402- ) {
1403- expand_until = i + 1 ;
1404- if candidate. match_pairs . len ( ) > 1 {
1405- break ;
1406- }
1407- }
1408- if expand_until != 0 {
1409- expand_until = i + 1 ;
1410- }
1411- }
1412- let ( candidates_to_expand, remaining_candidates) = candidates. split_at_mut ( expand_until) ;
1413-
1381+ )
1382+ } ) ;
14141383 ensure_sufficient_stack ( || {
1415- if candidates_to_expand . is_empty ( ) {
1384+ if !expand_ors {
14161385 // No candidates start with an or-pattern, we can continue.
14171386 self . match_expanded_candidates (
14181387 span,
14191388 scrutinee_span,
14201389 start_block,
14211390 otherwise_block,
1422- remaining_candidates ,
1391+ candidates ,
14231392 ) ;
14241393 } else {
1425- // Expand one level of or-patterns for each candidate in `candidates_to_expand`.
1426- let mut expanded_candidates = Vec :: new ( ) ;
1427- for candidate in candidates_to_expand. iter_mut ( ) {
1428- if let [ MatchPair { test_case : TestCase :: Or { .. } , .. } , ..] =
1429- & * candidate. match_pairs
1430- {
1431- let or_match_pair = candidate. match_pairs . remove ( 0 ) ;
1432- // Expand the or-pattern into subcandidates.
1433- self . create_or_subcandidates ( candidate, or_match_pair) ;
1434- // Collect the newly created subcandidates.
1435- for subcandidate in candidate. subcandidates . iter_mut ( ) {
1436- expanded_candidates. push ( subcandidate) ;
1437- }
1438- } else {
1439- expanded_candidates. push ( candidate) ;
1440- }
1441- }
1442-
1443- // Process the expanded candidates.
1444- let remainder_start = self . cfg . start_new_block ( ) ;
1445- // There might be new or-patterns obtained from expanding the old ones, so we call
1446- // `match_candidates` again.
1447- self . match_candidates (
1394+ self . expand_and_match_or_candidates (
14481395 span,
14491396 scrutinee_span,
14501397 start_block,
1451- remainder_start,
1452- expanded_candidates. as_mut_slice ( ) ,
1453- ) ;
1454-
1455- // Simplify subcandidates and process any leftover match pairs.
1456- for candidate in candidates_to_expand {
1457- if !candidate. subcandidates . is_empty ( ) {
1458- self . finalize_or_candidate ( span, scrutinee_span, candidate) ;
1459- }
1460- }
1461-
1462- // Process the remaining candidates.
1463- self . match_candidates (
1464- span,
1465- scrutinee_span,
1466- remainder_start,
14671398 otherwise_block,
1468- remaining_candidates ,
1399+ candidates ,
14691400 ) ;
14701401 }
14711402 } ) ;
@@ -1561,6 +1492,98 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
15611492 otherwise_block
15621493 }
15631494
1495+ /// Takes a list of candidates such that some of the candidates' first match pairs are
1496+ /// or-patterns, expands as many or-patterns as possible, and processes the resulting
1497+ /// candidates.
1498+ fn expand_and_match_or_candidates (
1499+ & mut self ,
1500+ span : Span ,
1501+ scrutinee_span : Span ,
1502+ start_block : BasicBlock ,
1503+ otherwise_block : BasicBlock ,
1504+ candidates : & mut [ & mut Candidate < ' _ , ' tcx > ] ,
1505+ ) {
1506+ // We can't expand or-patterns freely. The rule is: if the candidate has an
1507+ // or-pattern as its only remaining match pair, we can expand it freely. If it has
1508+ // other match pairs, we can expand it but we can't process more candidates after
1509+ // it.
1510+ //
1511+ // If we didn't stop, the `otherwise` cases could get mixed up. E.g. in the
1512+ // following, or-pattern simplification (in `merge_trivial_subcandidates`) makes it
1513+ // so the `1` and `2` cases branch to a same block (which then tests `false`). If we
1514+ // took `(2, _)` in the same set of candidates, when we reach the block that tests
1515+ // `false` we don't know whether we came from `1` or `2`, hence we can't know where
1516+ // to branch on failure.
1517+ //
1518+ // ```ignore(illustrative)
1519+ // match (1, true) {
1520+ // (1 | 2, false) => {},
1521+ // (2, _) => {},
1522+ // _ => {}
1523+ // }
1524+ // ```
1525+ //
1526+ // We therefore split the `candidates` slice in two, expand or-patterns in the first half,
1527+ // and process the rest separately.
1528+ let mut expand_until = 0 ;
1529+ for ( i, candidate) in candidates. iter ( ) . enumerate ( ) {
1530+ expand_until = i + 1 ;
1531+ if candidate. match_pairs . len ( ) > 1
1532+ && matches ! ( & candidate. match_pairs[ 0 ] . test_case, TestCase :: Or { .. } )
1533+ {
1534+ // The candidate has an or-pattern as well as more match pairs: we must
1535+ // split the candidates list here.
1536+ break ;
1537+ }
1538+ }
1539+ let ( candidates_to_expand, remaining_candidates) = candidates. split_at_mut ( expand_until) ;
1540+
1541+ // Expand one level of or-patterns for each candidate in `candidates_to_expand`.
1542+ let mut expanded_candidates = Vec :: new ( ) ;
1543+ for candidate in candidates_to_expand. iter_mut ( ) {
1544+ if let [ MatchPair { test_case : TestCase :: Or { .. } , .. } , ..] = & * candidate. match_pairs
1545+ {
1546+ let or_match_pair = candidate. match_pairs . remove ( 0 ) ;
1547+ // Expand the or-pattern into subcandidates.
1548+ self . create_or_subcandidates ( candidate, or_match_pair) ;
1549+ // Collect the newly created subcandidates.
1550+ for subcandidate in candidate. subcandidates . iter_mut ( ) {
1551+ expanded_candidates. push ( subcandidate) ;
1552+ }
1553+ } else {
1554+ expanded_candidates. push ( candidate) ;
1555+ }
1556+ }
1557+
1558+ // Process the expanded candidates.
1559+ let remainder_start = self . cfg . start_new_block ( ) ;
1560+ // There might be new or-patterns obtained from expanding the old ones, so we call
1561+ // `match_candidates` again.
1562+ self . match_candidates (
1563+ span,
1564+ scrutinee_span,
1565+ start_block,
1566+ remainder_start,
1567+ expanded_candidates. as_mut_slice ( ) ,
1568+ ) ;
1569+
1570+ // Simplify subcandidates and process any leftover match pairs.
1571+ for candidate in candidates_to_expand {
1572+ if !candidate. subcandidates . is_empty ( ) {
1573+ self . finalize_or_candidate ( span, scrutinee_span, candidate) ;
1574+ }
1575+ }
1576+
1577+ // Process the remaining candidates.
1578+ self . match_candidates (
1579+ span,
1580+ scrutinee_span,
1581+ remainder_start,
1582+ otherwise_block,
1583+ remaining_candidates,
1584+ ) ;
1585+ }
1586+
15641587 /// Given a match-pair that corresponds to an or-pattern, expand each subpattern into a new
15651588 /// subcandidate. Any candidate that has been expanded that way should be passed to
15661589 /// `finalize_or_candidate` after its subcandidates have been processed.
0 commit comments