From 780beda83c8b822a91b801050ee543f5f7a271df Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 18 Feb 2024 12:52:40 +0100 Subject: [PATCH 1/2] Tweak block management --- .../rustc_mir_build/src/build/matches/mod.rs | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index ccf299649cf..808b4a130e5 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1408,7 +1408,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { span: Span, scrutinee_span: Span, candidates: &mut [&mut Candidate<'_, 'tcx>], - block: BasicBlock, + start_block: BasicBlock, otherwise_block: BasicBlock, fake_borrows: &mut Option>>, ) { @@ -1423,7 +1423,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { span, scrutinee_span, candidates, - block, + start_block, otherwise_block, fake_borrows, ); @@ -1432,7 +1432,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } let match_pairs = mem::take(&mut first_candidate.match_pairs); - first_candidate.pre_binding_block = Some(block); let remainder_start = self.cfg.start_new_block(); for match_pair in match_pairs { @@ -1442,9 +1441,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let or_span = match_pair.pattern.span; first_candidate.visit_leaves(|leaf_candidate| { + let or_start = leaf_candidate.pre_binding_block.unwrap_or(start_block); + let or_otherwise = leaf_candidate.otherwise_block.unwrap_or(remainder_start); self.test_or_pattern( leaf_candidate, - remainder_start, + or_start, + or_otherwise, pats, or_span, &match_pair.place, @@ -1464,13 +1466,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } #[instrument( - skip(self, otherwise, or_span, place, fake_borrows, candidate, pats), + skip(self, start_block, otherwise_block, or_span, place, fake_borrows, candidate, pats), level = "debug" )] fn test_or_pattern<'pat>( &mut self, candidate: &mut Candidate<'pat, 'tcx>, - otherwise: BasicBlock, + start_block: BasicBlock, + otherwise_block: BasicBlock, pats: &'pat [Box>], or_span: Span, place: &PlaceBuilder<'tcx>, @@ -1482,16 +1485,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .map(|pat| Candidate::new(place.clone(), pat, candidate.has_guard, self)) .collect(); let mut or_candidate_refs: Vec<_> = or_candidates.iter_mut().collect(); - let otherwise = if let Some(otherwise_block) = candidate.otherwise_block { - otherwise_block - } else { - otherwise - }; self.match_candidates( or_span, or_span, - candidate.pre_binding_block.unwrap(), - otherwise, + start_block, + otherwise_block, &mut or_candidate_refs, fake_borrows, ); From c1514a6324cf80c52f7eb39b7a74df89b3769106 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 18 Feb 2024 22:58:14 +0100 Subject: [PATCH 2/2] Test one or pattern at a time --- .../rustc_mir_build/src/build/matches/mod.rs | 71 +++++++++++-------- 1 file changed, 42 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 808b4a130e5..88a5eae281b 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1052,7 +1052,7 @@ struct Ascription<'tcx> { variance: ty::Variance, } -#[derive(Debug)] +#[derive(Debug, Clone)] pub(crate) struct MatchPair<'pat, 'tcx> { // This place... place: PlaceBuilder<'tcx>, @@ -1413,48 +1413,61 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fake_borrows: &mut Option>>, ) { let (first_candidate, remaining_candidates) = candidates.split_first_mut().unwrap(); - - // All of the or-patterns have been sorted to the end, so if the first - // pattern is an or-pattern we only have or-patterns. - match first_candidate.match_pairs[0].pattern.kind { - PatKind::Or { .. } => (), - _ => { - self.test_candidates( - span, - scrutinee_span, - candidates, - start_block, - otherwise_block, - fake_borrows, - ); - return; - } + 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); + 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 remainder_start = self.cfg.start_new_block(); - for match_pair in match_pairs { - let PatKind::Or { ref pats } = &match_pair.pattern.kind else { - bug!("Or-patterns should have been sorted to the end"); - }; - let or_span = match_pair.pattern.span; + let or_span = first_match_pair.pattern.span; + // Test the alternatives of this or-pattern. + self.test_or_pattern( + first_candidate, + start_block, + remainder_start, + pats, + or_span, + &first_match_pair.place, + fake_borrows, + ); + if !remaining_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, ...)`. first_candidate.visit_leaves(|leaf_candidate| { - let or_start = leaf_candidate.pre_binding_block.unwrap_or(start_block); + 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_or_pattern( - leaf_candidate, + self.test_candidates_with_or( + span, + scrutinee_span, + &mut [leaf_candidate], or_start, or_otherwise, - pats, - or_span, - &match_pair.place, fake_borrows, ); }); } + // Test the remaining candidates. self.match_candidates( span, scrutinee_span, @@ -1462,7 +1475,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { otherwise_block, remaining_candidates, fake_borrows, - ) + ); } #[instrument(