Factor out finalize_or_candidate

This commit is contained in:
Nadrieril 2024-03-20 01:56:24 +01:00
parent 764f086f2c
commit ce374fcbc1

View File

@ -1575,21 +1575,52 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
let first_match_pair = first_candidate.match_pairs.remove(0);
let remaining_match_pairs = mem::take(&mut first_candidate.match_pairs);
let remainder_start = self.cfg.start_new_block();
// Test the alternatives of this or-pattern.
self.test_or_pattern(first_candidate, start_block, remainder_start, first_match_pair);
self.test_or_pattern(
span,
scrutinee_span,
first_candidate,
start_block,
remainder_start,
first_match_pair,
);
if !remaining_match_pairs.is_empty() {
// Test the remaining candidates.
self.match_candidates(
span,
scrutinee_span,
remainder_start,
otherwise_block,
remaining_candidates,
);
}
/// Simplify subcandidates and process any leftover match pairs. The candidate should have been
/// expanded with `create_or_subcandidates`.
fn finalize_or_candidate(
&mut self,
span: Span,
scrutinee_span: Span,
candidate: &mut Candidate<'_, 'tcx>,
) {
if candidate.subcandidates.is_empty() {
return;
}
self.merge_trivial_subcandidates(candidate);
if !candidate.match_pairs.is_empty() {
// If more match pairs remain, test them after each subcandidate.
// 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, ...)`.
let mut last_otherwise = None;
first_candidate.visit_leaves(|leaf_candidate| {
candidate.visit_leaves(|leaf_candidate| {
last_otherwise = leaf_candidate.otherwise_block;
});
first_candidate.visit_leaves(|leaf_candidate| {
let remaining_match_pairs = mem::take(&mut candidate.match_pairs);
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();
@ -1612,20 +1643,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
);
});
}
// Test the remaining candidates.
self.match_candidates(
span,
scrutinee_span,
remainder_start,
otherwise_block,
remaining_candidates,
);
}
#[instrument(skip(self, start_block, otherwise_block, candidate, match_pair), level = "debug")]
fn test_or_pattern<'pat>(
&mut self,
span: Span,
scrutinee_span: Span,
candidate: &mut Candidate<'pat, 'tcx>,
start_block: BasicBlock,
otherwise_block: BasicBlock,
@ -1641,12 +1665,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
otherwise_block,
&mut or_candidate_refs,
);
self.merge_trivial_subcandidates(candidate);
self.finalize_or_candidate(span, scrutinee_span, candidate);
}
/// 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
/// `merge_trivial_subcandidates` after its subcandidates have been processed.
/// `finalize_or_candidate` after its subcandidates have been processed.
fn create_or_subcandidates<'pat>(
&mut self,
candidate: &mut Candidate<'pat, 'tcx>,
@ -1664,8 +1688,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
/// Try to merge all of the subcandidates of the given candidate into one. This avoids
/// exponentially large CFGs in cases like `(1 | 2, 3 | 4, ...)`. The or-pattern should have
/// been expanded with `create_or_subcandidates`.
/// exponentially large CFGs in cases like `(1 | 2, 3 | 4, ...)`. The candidate should have been
/// expanded with `create_or_subcandidates`.
fn merge_trivial_subcandidates(&mut self, candidate: &mut Candidate<'_, 'tcx>) {
if candidate.subcandidates.is_empty() || candidate.has_guard {
// FIXME(or_patterns; matthewjasper) Don't give up if we have a guard.