Skip to content

Commit 6bb6b81

Browse files
committed
Auto merge of #122046 - Nadrieril:integrate-or-pats2, r=matthewjasper
match lowering: handle or-patterns one layer at a time `create_or_subcandidates` and `merge_trivial_subcandidates` both call themselves recursively to handle nested or-patterns, which is hard to follow. In this PR I avoid the need for that; we now process a single "layer" of or-patterns at a time. By calling back into `match_candidates`, we only need to expand one layer at a time. Conversely, since we always try to simplify a layer that we just expanded (thanks to #123067), we only have to merge one layer at a time. r? `@matthewjasper`
2 parents 3d5528c + 7410f78 commit 6bb6b81

File tree

2 files changed

+38
-65
lines changed

2 files changed

+38
-65
lines changed

Diff for: compiler/rustc_mir_build/src/build/matches/mod.rs

+37-41
Original file line numberDiff line numberDiff line change
@@ -1270,9 +1270,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
12701270
) {
12711271
let mut split_or_candidate = false;
12721272
for candidate in &mut *candidates {
1273-
if let [MatchPair { test_case: TestCase::Or { pats, .. }, .. }] =
1274-
&*candidate.match_pairs
1275-
{
1273+
if let [MatchPair { test_case: TestCase::Or { .. }, .. }] = &*candidate.match_pairs {
12761274
// Split a candidate in which the only match-pair is an or-pattern into multiple
12771275
// candidates. This is so that
12781276
//
@@ -1282,9 +1280,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
12821280
// }
12831281
//
12841282
// only generates a single switch.
1285-
candidate.subcandidates = self.create_or_subcandidates(pats, candidate.has_guard);
1286-
let first_match_pair = candidate.match_pairs.pop().unwrap();
1287-
candidate.or_span = Some(first_match_pair.pattern.span);
1283+
let match_pair = candidate.match_pairs.pop().unwrap();
1284+
self.create_or_subcandidates(candidate, match_pair);
12881285
split_or_candidate = true;
12891286
}
12901287
}
@@ -1297,7 +1294,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
12971294
for candidate in candidates.iter_mut() {
12981295
candidate.visit_leaves(|leaf_candidate| new_candidates.push(leaf_candidate));
12991296
}
1300-
self.match_simplified_candidates(
1297+
self.match_candidates(
13011298
span,
13021299
scrutinee_span,
13031300
start_block,
@@ -1472,14 +1469,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
14721469
return;
14731470
}
14741471

1475-
let match_pairs = mem::take(&mut first_candidate.match_pairs);
1476-
let (first_match_pair, remaining_match_pairs) = match_pairs.split_first().unwrap();
1477-
let TestCase::Or { ref pats } = &first_match_pair.test_case else { unreachable!() };
1478-
1472+
let first_match_pair = first_candidate.match_pairs.remove(0);
1473+
let remaining_match_pairs = mem::take(&mut first_candidate.match_pairs);
14791474
let remainder_start = self.cfg.start_new_block();
1480-
let or_span = first_match_pair.pattern.span;
14811475
// Test the alternatives of this or-pattern.
1482-
self.test_or_pattern(first_candidate, start_block, remainder_start, pats, or_span);
1476+
self.test_or_pattern(first_candidate, start_block, remainder_start, first_match_pair);
14831477

14841478
if !remaining_match_pairs.is_empty() {
14851479
// If more match pairs remain, test them after each subcandidate.
@@ -1514,56 +1508,58 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
15141508
);
15151509
}
15161510

1517-
#[instrument(
1518-
skip(self, start_block, otherwise_block, or_span, candidate, pats),
1519-
level = "debug"
1520-
)]
1511+
#[instrument(skip(self, start_block, otherwise_block, candidate, match_pair), level = "debug")]
15211512
fn test_or_pattern<'pat>(
15221513
&mut self,
15231514
candidate: &mut Candidate<'pat, 'tcx>,
15241515
start_block: BasicBlock,
15251516
otherwise_block: BasicBlock,
1526-
pats: &[FlatPat<'pat, 'tcx>],
1527-
or_span: Span,
1517+
match_pair: MatchPair<'pat, 'tcx>,
15281518
) {
1529-
debug!("candidate={:#?}\npats={:#?}", candidate, pats);
1530-
let mut or_candidates: Vec<_> = pats
1531-
.iter()
1532-
.cloned()
1533-
.map(|flat_pat| Candidate::from_flat_pat(flat_pat, candidate.has_guard))
1534-
.collect();
1535-
let mut or_candidate_refs: Vec<_> = or_candidates.iter_mut().collect();
1519+
let or_span = match_pair.pattern.span;
1520+
self.create_or_subcandidates(candidate, match_pair);
1521+
let mut or_candidate_refs: Vec<_> = candidate.subcandidates.iter_mut().collect();
15361522
self.match_candidates(
15371523
or_span,
15381524
or_span,
15391525
start_block,
15401526
otherwise_block,
15411527
&mut or_candidate_refs,
15421528
);
1543-
candidate.subcandidates = or_candidates;
1544-
candidate.or_span = Some(or_span);
15451529
self.merge_trivial_subcandidates(candidate);
15461530
}
15471531

1548-
/// Try to merge all of the subcandidates of the given candidate into one.
1549-
/// This avoids exponentially large CFGs in cases like `(1 | 2, 3 | 4, ...)`.
1532+
/// Given a match-pair that corresponds to an or-pattern, expand each subpattern into a new
1533+
/// subcandidate. Any candidate that has been expanded that way should be passed to
1534+
/// `merge_trivial_subcandidates` after its subcandidates have been processed.
1535+
fn create_or_subcandidates<'pat>(
1536+
&mut self,
1537+
candidate: &mut Candidate<'pat, 'tcx>,
1538+
match_pair: MatchPair<'pat, 'tcx>,
1539+
) {
1540+
let TestCase::Or { pats } = match_pair.test_case else { bug!() };
1541+
debug!("expanding or-pattern: candidate={:#?}\npats={:#?}", candidate, pats);
1542+
candidate.or_span = Some(match_pair.pattern.span);
1543+
candidate.subcandidates = pats
1544+
.into_vec()
1545+
.into_iter()
1546+
.map(|flat_pat| Candidate::from_flat_pat(flat_pat, candidate.has_guard))
1547+
.collect();
1548+
}
1549+
1550+
/// Try to merge all of the subcandidates of the given candidate into one. This avoids
1551+
/// exponentially large CFGs in cases like `(1 | 2, 3 | 4, ...)`. The or-pattern should have
1552+
/// been expanded with `create_or_subcandidates`.
15501553
fn merge_trivial_subcandidates(&mut self, candidate: &mut Candidate<'_, 'tcx>) {
15511554
if candidate.subcandidates.is_empty() || candidate.has_guard {
15521555
// FIXME(or_patterns; matthewjasper) Don't give up if we have a guard.
15531556
return;
15541557
}
15551558

1556-
let mut can_merge = true;
1557-
1558-
// Not `Iterator::all` because we don't want to short-circuit.
1559-
for subcandidate in &mut candidate.subcandidates {
1560-
self.merge_trivial_subcandidates(subcandidate);
1561-
1562-
// FIXME(or_patterns; matthewjasper) Try to be more aggressive here.
1563-
can_merge &=
1564-
subcandidate.subcandidates.is_empty() && subcandidate.extra_data.is_empty();
1565-
}
1566-
1559+
// FIXME(or_patterns; matthewjasper) Try to be more aggressive here.
1560+
let can_merge = candidate.subcandidates.iter().all(|subcandidate| {
1561+
subcandidate.subcandidates.is_empty() && subcandidate.extra_data.is_empty()
1562+
});
15671563
if can_merge {
15681564
let any_matches = self.cfg.start_new_block();
15691565
let or_span = candidate.or_span.take().unwrap();

Diff for: compiler/rustc_mir_build/src/build/matches/simplify.rs

+1-24
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
//! sort of test: for example, testing which variant an enum is, or
1313
//! testing a value against a constant.
1414
15-
use crate::build::matches::{Candidate, FlatPat, MatchPair, PatternExtraData, TestCase};
15+
use crate::build::matches::{MatchPair, PatternExtraData, TestCase};
1616
use crate::build::Builder;
1717

1818
use std::mem;
@@ -66,27 +66,4 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
6666
match_pairs.sort_by_key(|pair| matches!(pair.test_case, TestCase::Or { .. }));
6767
debug!(simplified = ?match_pairs, "simplify_match_pairs");
6868
}
69-
70-
/// Create a new candidate for each pattern in `pats`, and recursively simplify tje
71-
/// single-or-pattern case.
72-
pub(super) fn create_or_subcandidates<'pat>(
73-
&mut self,
74-
pats: &[FlatPat<'pat, 'tcx>],
75-
has_guard: bool,
76-
) -> Vec<Candidate<'pat, 'tcx>> {
77-
pats.iter()
78-
.cloned()
79-
.map(|flat_pat| {
80-
let mut candidate = Candidate::from_flat_pat(flat_pat, has_guard);
81-
if let [MatchPair { test_case: TestCase::Or { pats, .. }, .. }] =
82-
&*candidate.match_pairs
83-
{
84-
candidate.subcandidates = self.create_or_subcandidates(pats, has_guard);
85-
let first_match_pair = candidate.match_pairs.pop().unwrap();
86-
candidate.or_span = Some(first_match_pair.pattern.span);
87-
}
88-
candidate
89-
})
90-
.collect()
91-
}
9269
}

0 commit comments

Comments
 (0)