Skip to content

match lowering: Clarify the main loop of the algorithm #127164

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jul 12, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Move or-pattern expansion inside the main part of the algorithm
Nadrieril committed Jul 9, 2024
commit c5062f73181778af278321827ceedf1682ee0a8b
60 changes: 24 additions & 36 deletions compiler/rustc_mir_build/src/build/matches/mod.rs
Original file line number Diff line number Diff line change
@@ -1119,6 +1119,11 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
}
}

/// Returns whether the first match pair of this candidate is an or-pattern.
fn starts_with_or_pattern(&self) -> bool {
matches!(&*self.match_pairs, [MatchPair { test_case: TestCase::Or { .. }, .. }, ..])
}

/// Visit the leaf candidates (those with no subcandidates) contained in
/// this candidate.
fn visit_leaves<'a>(&'a mut self, mut visit_leaf: impl FnMut(&'a mut Self)) {
@@ -1435,39 +1440,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
otherwise_block: BasicBlock,
candidates: &mut [&mut Candidate<'_, 'tcx>],
) {
// If any candidate starts with an or-pattern, we have to expand the or-pattern before we
// can proceed further.
let expand_ors = candidates.iter().any(|candidate| {
matches!(
&*candidate.match_pairs,
[MatchPair { test_case: TestCase::Or { .. }, .. }, ..]
)
});
ensure_sufficient_stack(|| {
if !expand_ors {
// No candidates start with an or-pattern, we can continue.
self.match_expanded_candidates(
span,
scrutinee_span,
start_block,
otherwise_block,
candidates,
);
} else {
self.expand_and_match_or_candidates(
span,
scrutinee_span,
start_block,
otherwise_block,
candidates,
);
}
self.match_candidates_with_enough_stack(
span,
scrutinee_span,
start_block,
otherwise_block,
candidates,
)
});
}

/// Construct the decision tree for `candidates`. Caller must ensure that no candidate in
/// `candidates` starts with an or-pattern.
fn match_expanded_candidates(
/// Construct the decision tree for `candidates`. Don't call this, call `match_candidates`
/// instead to reserve sufficient stack space.
fn match_candidates_with_enough_stack(
&mut self,
span: Span,
scrutinee_span: Span,
@@ -1492,12 +1478,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// The first candidate has satisfied all its match pairs; we link it up and continue
// with the remaining candidates.
start_block = self.select_matched_candidate(first, start_block);
self.match_expanded_candidates(
self.match_candidates(span, scrutinee_span, start_block, otherwise_block, remaining)
}
candidates if candidates.iter().any(|candidate| candidate.starts_with_or_pattern()) => {
// If any candidate starts with an or-pattern, we have to expand the or-pattern before we
// can proceed further.
self.expand_and_match_or_candidates(
span,
scrutinee_span,
start_block,
otherwise_block,
remaining,
candidates,
)
}
candidates => {
@@ -1591,9 +1582,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let mut expand_until = 0;
for (i, candidate) in candidates.iter().enumerate() {
expand_until = i + 1;
if candidate.match_pairs.len() > 1
&& matches!(&candidate.match_pairs[0].test_case, TestCase::Or { .. })
{
if candidate.match_pairs.len() > 1 && candidate.starts_with_or_pattern() {
// The candidate has an or-pattern as well as more match pairs: we must
// split the candidates list here.
break;
@@ -1604,8 +1593,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// Expand one level of or-patterns for each candidate in `candidates_to_expand`.
let mut expanded_candidates = Vec::new();
for candidate in candidates_to_expand.iter_mut() {
if let [MatchPair { test_case: TestCase::Or { .. }, .. }, ..] = &*candidate.match_pairs
{
if candidate.starts_with_or_pattern() {
let or_match_pair = candidate.match_pairs.remove(0);
// Expand the or-pattern into subcandidates.
self.create_or_subcandidates(candidate, or_match_pair);