Skip to content

Rollup of 6 pull requests #127635

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 20 commits into from
Jul 12, 2024
Merged
Changes from 1 commit
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
585ca16
as_simd: fix comment to be in line with 507583a (#121201)
greaka Jul 6, 2024
5bf50e6
Move a function
Nadrieril Jun 30, 2024
bff4d21
Factor out the special handling of or-patterns
Nadrieril Jun 30, 2024
c5062f7
Move or-pattern expansion inside the main part of the algorithm
Nadrieril Jun 30, 2024
8a222ff
Don't try to save an extra block
Nadrieril Jun 30, 2024
fc40247
Factor out the "process remaining candidates" cases
Nadrieril Jun 30, 2024
3e030b3
Return the `otherwise_block` instead of passing it as argument
Nadrieril Jun 30, 2024
42772e9
Address review comments
Nadrieril Jul 5, 2024
08a2992
compiletest: Better error message for bad `normalize-*` headers
Zalathar Jul 11, 2024
b77d3ef
Mark builtin syntax as internal
compiler-errors Jul 11, 2024
d902179
Revert accidental comment deletion
SkiFire13 Jul 11, 2024
d9170dc
Add regression test for issue 127545
tesuji Jul 11, 2024
872d7b8
Add suggestion for `Option<&Vec<T>> -> Option<&[T]`
tesuji Jul 11, 2024
a776e5f
Add doc for deconstruct_option_or_result
tesuji Jul 11, 2024
58fe37f
Rollup merge of #127164 - Nadrieril:clean-lowering-loop, r=matthewjasper
matthiaskrgr Jul 12, 2024
1e7ad4c
Rollup merge of #127422 - greaka:master, r=workingjubilee
matthiaskrgr Jul 12, 2024
83d1a1b
Rollup merge of #127596 - tesuji:help-unwrap-or, r=compiler-errors
matthiaskrgr Jul 12, 2024
fe564c1
Rollup merge of #127607 - Zalathar:normalize-hint, r=wesleywiser
matthiaskrgr Jul 12, 2024
ca576ea
Rollup merge of #127622 - compiler-errors:builtin-internal, r=lqd
matthiaskrgr Jul 12, 2024
c2b7842
Rollup merge of #127625 - SkiFire13:revert-comment-deletion, r=workin…
matthiaskrgr Jul 12, 2024
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
Factor out the special handling of or-patterns
  • Loading branch information
Nadrieril committed Jul 9, 2024
commit bff4d213fac5ba32b51d320800700124205f6565
185 changes: 104 additions & 81 deletions compiler/rustc_mir_build/src/build/matches/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1427,108 +1427,39 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// Note how we test `x` twice. This is the tradeoff of backtracking automata: we prefer smaller
/// code size at the expense of non-optimal code paths.
#[instrument(skip(self), level = "debug")]
fn match_candidates<'pat>(
fn match_candidates(
&mut self,
span: Span,
scrutinee_span: Span,
start_block: BasicBlock,
otherwise_block: BasicBlock,
candidates: &mut [&mut Candidate<'pat, 'tcx>],
candidates: &mut [&mut Candidate<'_, 'tcx>],
) {
// We process or-patterns here. If any candidate starts with an or-pattern, we have to
// expand the or-pattern before we can proceed further.
//
// We can't expand them freely however. The rule is: if the candidate has an or-pattern as
// its only remaining match pair, we can expand it freely. If it has other match pairs, we
// can expand it but we can't process more candidates after it.
//
// If we didn't stop, the `otherwise` cases could get mixed up. E.g. in the following,
// or-pattern simplification (in `merge_trivial_subcandidates`) makes it so the `1` and `2`
// cases branch to a same block (which then tests `false`). If we took `(2, _)` in the same
// set of candidates, when we reach the block that tests `false` we don't know whether we
// came from `1` or `2`, hence we can't know where to branch on failure.
// ```ignore(illustrative)
// match (1, true) {
// (1 | 2, false) => {},
// (2, _) => {},
// _ => {}
// }
// ```
//
// We therefore split the `candidates` slice in two, expand or-patterns in the first half,
// and process both halves separately.
let mut expand_until = 0;
for (i, candidate) in candidates.iter().enumerate() {
if matches!(
// 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 { .. }, .. }, ..]
) {
expand_until = i + 1;
if candidate.match_pairs.len() > 1 {
break;
}
}
if expand_until != 0 {
expand_until = i + 1;
}
}
let (candidates_to_expand, remaining_candidates) = candidates.split_at_mut(expand_until);

)
});
ensure_sufficient_stack(|| {
if candidates_to_expand.is_empty() {
if !expand_ors {
// No candidates start with an or-pattern, we can continue.
self.match_expanded_candidates(
span,
scrutinee_span,
start_block,
otherwise_block,
remaining_candidates,
candidates,
);
} else {
// 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
{
let or_match_pair = candidate.match_pairs.remove(0);
// Expand the or-pattern into subcandidates.
self.create_or_subcandidates(candidate, or_match_pair);
// Collect the newly created subcandidates.
for subcandidate in candidate.subcandidates.iter_mut() {
expanded_candidates.push(subcandidate);
}
} else {
expanded_candidates.push(candidate);
}
}

// Process the expanded candidates.
let remainder_start = self.cfg.start_new_block();
// There might be new or-patterns obtained from expanding the old ones, so we call
// `match_candidates` again.
self.match_candidates(
self.expand_and_match_or_candidates(
span,
scrutinee_span,
start_block,
remainder_start,
expanded_candidates.as_mut_slice(),
);

// Simplify subcandidates and process any leftover match pairs.
for candidate in candidates_to_expand {
if !candidate.subcandidates.is_empty() {
self.finalize_or_candidate(span, scrutinee_span, candidate);
}
}

// Process the remaining candidates.
self.match_candidates(
span,
scrutinee_span,
remainder_start,
otherwise_block,
remaining_candidates,
candidates,
);
}
});
Expand Down Expand Up @@ -1624,6 +1555,98 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
otherwise_block
}

/// Takes a list of candidates such that some of the candidates' first match pairs are
/// or-patterns, expands as many or-patterns as possible, and processes the resulting
/// candidates.
fn expand_and_match_or_candidates(
&mut self,
span: Span,
scrutinee_span: Span,
start_block: BasicBlock,
otherwise_block: BasicBlock,
candidates: &mut [&mut Candidate<'_, 'tcx>],
) {
// We can't expand or-patterns freely. The rule is: if the candidate has an
// or-pattern as its only remaining match pair, we can expand it freely. If it has
// other match pairs, we can expand it but we can't process more candidates after
// it.
//
// If we didn't stop, the `otherwise` cases could get mixed up. E.g. in the
// following, or-pattern simplification (in `merge_trivial_subcandidates`) makes it
// so the `1` and `2` cases branch to a same block (which then tests `false`). If we
// took `(2, _)` in the same set of candidates, when we reach the block that tests
// `false` we don't know whether we came from `1` or `2`, hence we can't know where
// to branch on failure.
//
// ```ignore(illustrative)
// match (1, true) {
// (1 | 2, false) => {},
// (2, _) => {},
// _ => {}
// }
// ```
//
// We therefore split the `candidates` slice in two, expand or-patterns in the first half,
// and process the rest separately.
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 { .. })
{
// The candidate has an or-pattern as well as more match pairs: we must
// split the candidates list here.
break;
}
}
let (candidates_to_expand, remaining_candidates) = candidates.split_at_mut(expand_until);

// 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
{
let or_match_pair = candidate.match_pairs.remove(0);
// Expand the or-pattern into subcandidates.
self.create_or_subcandidates(candidate, or_match_pair);
// Collect the newly created subcandidates.
for subcandidate in candidate.subcandidates.iter_mut() {
expanded_candidates.push(subcandidate);
}
} else {
expanded_candidates.push(candidate);
}
}

// Process the expanded candidates.
let remainder_start = self.cfg.start_new_block();
// There might be new or-patterns obtained from expanding the old ones, so we call
// `match_candidates` again.
self.match_candidates(
span,
scrutinee_span,
start_block,
remainder_start,
expanded_candidates.as_mut_slice(),
);

// Simplify subcandidates and process any leftover match pairs.
for candidate in candidates_to_expand {
if !candidate.subcandidates.is_empty() {
self.finalize_or_candidate(span, scrutinee_span, candidate);
}
}

// Process the remaining candidates.
self.match_candidates(
span,
scrutinee_span,
remainder_start,
otherwise_block,
remaining_candidates,
);
}

/// Given a match-pair that corresponds to an or-pattern, expand each subpattern into a new
/// subcandidate. Any candidate that has been expanded that way should be passed to
/// `finalize_or_candidate` after its subcandidates have been processed.
Expand Down