Skip to content

Commit

Permalink
Move a bit of the logic to match_simplified_candidates
Browse files Browse the repository at this point in the history
  • Loading branch information
Nadrieril committed Feb 21, 2024
1 parent e712fb6 commit 95b968e
Showing 1 changed file with 42 additions and 40 deletions.
82 changes: 42 additions & 40 deletions compiler/rustc_mir_build/src/build/matches/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1260,9 +1260,34 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
fake_borrows,
)
}
[first, remaining @ ..]
if matches!(first.match_pairs[0].pattern.kind, PatKind::Or { .. }) =>
{
// The first candidate has an or-pattern.
let remainder_start = self.cfg.start_new_block();
// Test the or-pattern.
self.test_or_candidate(
span,
scrutinee_span,
first,
start_block,
remainder_start,
fake_borrows,
);
// Test the remaining candidates.
self.match_candidates(
span,
scrutinee_span,
remainder_start,
otherwise_block,
remaining,
fake_borrows,
);
}
candidates => {
// The first candidate has some unsatisfied match pairs; we proceed to do more tests.
self.test_candidates_with_or(
// The first candidate has some unsatisfied match pairs that aren't or-patterns; we
// proceed to do more tests.
self.test_candidates(
span,
scrutinee_span,
candidates,
Expand Down Expand Up @@ -1350,8 +1375,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
otherwise_block
}

/// Tests a candidate where there are only or-patterns left to test, or
/// forwards to [Builder::test_candidates].
/// Tests a candidate whose first match-pair is an or-pattern.
///
/// Given a pattern `(P | Q, R | S)` we (in principle) generate a CFG like
/// so:
Expand Down Expand Up @@ -1403,40 +1427,28 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// |
/// ...
/// ```
fn test_candidates_with_or(
fn test_or_candidate(
&mut self,
span: Span,
scrutinee_span: Span,
candidates: &mut [&mut Candidate<'_, 'tcx>],
candidate: &mut Candidate<'_, 'tcx>,
start_block: BasicBlock,
otherwise_block: BasicBlock,
fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>,
) {
let (first_candidate, remaining_candidates) = candidates.split_first_mut().unwrap();
assert!(first_candidate.subcandidates.is_empty());
if !matches!(first_candidate.match_pairs[0].pattern.kind, PatKind::Or { .. }) {
self.test_candidates(
span,
scrutinee_span,
candidates,
start_block,
otherwise_block,
fake_borrows,
);
return;
}

let match_pairs = mem::take(&mut first_candidate.match_pairs);
assert!(candidate.subcandidates.is_empty());
let match_pairs = mem::take(&mut candidate.match_pairs);
let (first_match_pair, remaining_match_pairs) = match_pairs.split_first().unwrap();
let PatKind::Or { ref pats } = &first_match_pair.pattern.kind else { unreachable!() };
let PatKind::Or { ref pats } = &first_match_pair.pattern.kind else {
bug!("Only call `test_or_candidate` if the first match pair is an or-pattern")
};

let remainder_start = self.cfg.start_new_block();
let or_span = first_match_pair.pattern.span;
// Test the alternatives of this or-pattern.
self.test_or_pattern(
first_candidate,
candidate,
start_block,
remainder_start,
otherwise_block,
pats,
or_span,
&first_match_pair.place,
Expand All @@ -1448,34 +1460,24 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// We could add them to the or-candidates before the call to `test_or_pattern` but this
// would make it impossible to detect simplifiable or-patterns. That would guarantee
// exponentially large CFGs for cases like `(1 | 2, 3 | 4, ...)`.
first_candidate.visit_leaves(|leaf_candidate| {
candidate.visit_leaves(|leaf_candidate| {
assert!(leaf_candidate.match_pairs.is_empty());
leaf_candidate.match_pairs.extend(remaining_match_pairs.iter().cloned());
let or_start = leaf_candidate.pre_binding_block.unwrap();
// In a case like `(a | b, c | d)`, if `a` succeeds and `c | d` fails, we know `(b,
// c | d)` will fail too. If there is no guard, we skip testing of `b` by branching
// directly to `remainder_start`. If there is a guard, we have to try `(b, c | d)`.
let or_otherwise = leaf_candidate.otherwise_block.unwrap_or(remainder_start);
self.test_candidates_with_or(
// directly to `otherwise_block`. If there is a guard, we have to try `(b, c | d)`.
let or_otherwise = leaf_candidate.otherwise_block.unwrap_or(otherwise_block);
self.match_simplified_candidates(
span,
scrutinee_span,
&mut [leaf_candidate],
or_start,
or_otherwise,
&mut [leaf_candidate],
fake_borrows,
);
});
}

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

#[instrument(
Expand Down

0 comments on commit 95b968e

Please sign in to comment.