Skip to content

Commit 806ee5f

Browse files
committed
Test one or pattern at a time
1 parent 442f3e7 commit 806ee5f

File tree

1 file changed

+41
-28
lines changed
  • compiler/rustc_mir_build/src/build/matches

1 file changed

+41
-28
lines changed

compiler/rustc_mir_build/src/build/matches/mod.rs

+41-28
Original file line numberDiff line numberDiff line change
@@ -1426,56 +1426,69 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
14261426
fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>,
14271427
) {
14281428
let (first_candidate, remaining_candidates) = candidates.split_first_mut().unwrap();
1429-
1430-
// All of the or-patterns have been sorted to the end, so if the first
1431-
// pattern is an or-pattern we only have or-patterns.
1432-
match first_candidate.match_pairs[0].pattern.kind {
1433-
PatKind::Or { .. } => (),
1434-
_ => {
1435-
self.test_candidates(
1436-
span,
1437-
scrutinee_span,
1438-
candidates,
1439-
start_block,
1440-
otherwise_block,
1441-
fake_borrows,
1442-
);
1443-
return;
1444-
}
1429+
assert!(first_candidate.subcandidates.is_empty());
1430+
if !matches!(first_candidate.match_pairs[0].pattern.kind, PatKind::Or { .. }) {
1431+
self.test_candidates(
1432+
span,
1433+
scrutinee_span,
1434+
candidates,
1435+
start_block,
1436+
otherwise_block,
1437+
fake_borrows,
1438+
);
1439+
return;
14451440
}
14461441

14471442
let match_pairs = mem::take(&mut first_candidate.match_pairs);
1443+
let (first_match_pair, remaining_match_pairs) = match_pairs.split_first().unwrap();
1444+
let PatKind::Or { ref pats } = &first_match_pair.pattern.kind else { unreachable!() };
14481445

14491446
let remainder_start = self.cfg.start_new_block();
1450-
for match_pair in match_pairs {
1451-
let PatKind::Or { ref pats } = &match_pair.pattern.kind else {
1452-
bug!("Or-patterns should have been sorted to the end");
1453-
};
1454-
let or_span = match_pair.pattern.span;
1447+
let or_span = first_match_pair.pattern.span;
1448+
// Test the alternatives of this or-pattern.
1449+
self.test_or_pattern(
1450+
first_candidate,
1451+
start_block,
1452+
remainder_start,
1453+
pats,
1454+
or_span,
1455+
&first_match_pair.place,
1456+
fake_borrows,
1457+
);
14551458

1459+
if !remaining_match_pairs.is_empty() {
1460+
// If more match pairs remain, test them after each subcandidate.
1461+
// We could add them to the or-candidates before the call to `test_or_pattern` but this
1462+
// would make it impossible to detect simplifiable or-patterns. That would guarantee
1463+
// exponentially large CFGs for cases like `(1 | 2, 3 | 4, ...)`.
14561464
first_candidate.visit_leaves(|leaf_candidate| {
1457-
let or_start = leaf_candidate.pre_binding_block.unwrap_or(start_block);
1465+
assert!(leaf_candidate.match_pairs.is_empty());
1466+
leaf_candidate.match_pairs.extend(remaining_match_pairs.iter().cloned());
1467+
let or_start = leaf_candidate.pre_binding_block.unwrap();
1468+
// In a case like `(a | b, c | d)`, if `a` succeeds and `c | d` fails, we know `(b,
1469+
// c | d)` will fail too. If there is no guard, we skip testing of `b` by branching
1470+
// directly to `remainder_start`. If there is a guard, we have to try `(b, c | d)`.
14581471
let or_otherwise = leaf_candidate.otherwise_block.unwrap_or(remainder_start);
1459-
self.test_or_pattern(
1460-
leaf_candidate,
1472+
self.test_candidates_with_or(
1473+
span,
1474+
scrutinee_span,
1475+
&mut [leaf_candidate],
14611476
or_start,
14621477
or_otherwise,
1463-
pats,
1464-
or_span,
1465-
&match_pair.place,
14661478
fake_borrows,
14671479
);
14681480
});
14691481
}
14701482

1483+
// Test the remaining candidates.
14711484
self.match_candidates(
14721485
span,
14731486
scrutinee_span,
14741487
remainder_start,
14751488
otherwise_block,
14761489
remaining_candidates,
14771490
fake_borrows,
1478-
)
1491+
);
14791492
}
14801493

14811494
#[instrument(

0 commit comments

Comments
 (0)