Skip to content

Commit 1e01a25

Browse files
committed
Factor out the special handling of or-patterns
1 parent 64692d4 commit 1e01a25

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
@@ -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

Comments
 (0)