Skip to content

Commit bff4d21

Browse files
committed
Factor out the special handling of or-patterns
1 parent 5bf50e6 commit bff4d21

File tree

1 file changed

+104
-81
lines changed
  • compiler/rustc_mir_build/src/build/matches

1 file changed

+104
-81
lines changed

compiler/rustc_mir_build/src/build/matches/mod.rs

+104-81
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)