Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 7a66fe0

Browse files
committed
Auto merge of rust-lang#121715 - Nadrieril:testcase-or, r=<try>
match lowering: pre-simplify or-patterns too This is the final part of my work to simplify match pairs early: now we do it for or-patterns too. This makes it possible to collect fake borrows separately from the main match lowering algorithm. That'll enable more simplifications of or-pattern handling. Note: I was tempted to have `Candidate` contain a `FlatPat`, but there are so many places that use `candidate.match_pairs` etc directly that I chose not to. r? `@matthewjasper`
2 parents ef32456 + ae1e1bd commit 7a66fe0

File tree

3 files changed

+155
-122
lines changed

3 files changed

+155
-122
lines changed

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

Lines changed: 63 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -315,20 +315,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
315315
// The set of places that we are creating fake borrows of. If there are
316316
// no match guards then we don't need any fake borrows, so don't track
317317
// them.
318-
let mut fake_borrows = match_has_guard.then(FxIndexSet::default);
318+
let fake_borrows = match_has_guard
319+
.then(|| util::FakeBorrowCollector::collect_fake_borrows(self, candidates));
319320

320321
let otherwise_block = self.cfg.start_new_block();
321322

322323
// This will generate code to test scrutinee_place and
323324
// branch to the appropriate arm block
324-
self.match_candidates(
325-
match_start_span,
326-
scrutinee_span,
327-
block,
328-
otherwise_block,
329-
candidates,
330-
&mut fake_borrows,
331-
);
325+
self.match_candidates(match_start_span, scrutinee_span, block, otherwise_block, candidates);
332326

333327
// See the doc comment on `match_candidates` for why we may have an
334328
// otherwise block. Match checking will ensure this is actually
@@ -938,6 +932,40 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
938932
}
939933
}
940934

935+
/// A pattern in a form suitable for generating code.
936+
#[derive(Debug, Clone)]
937+
struct FlatPat<'pat, 'tcx> {
938+
/// [`Span`] of the original pattern.
939+
span: Span,
940+
941+
/// To match the pattern, all of these must be satisfied...
942+
// Invariant: all the `MatchPair`s are recursively simplified.
943+
// Invariant: or-patterns must be sorted to the end.
944+
match_pairs: Vec<MatchPair<'pat, 'tcx>>,
945+
946+
/// ...these bindings established...
947+
bindings: Vec<Binding<'tcx>>,
948+
949+
/// ...and these types asserted.
950+
ascriptions: Vec<Ascription<'tcx>>,
951+
}
952+
953+
impl<'tcx, 'pat> FlatPat<'pat, 'tcx> {
954+
fn new(
955+
place: PlaceBuilder<'tcx>,
956+
pattern: &'pat Pat<'tcx>,
957+
cx: &mut Builder<'_, 'tcx>,
958+
) -> Self {
959+
let mut match_pairs = vec![MatchPair::new(place, pattern, cx)];
960+
let mut bindings = Vec::new();
961+
let mut ascriptions = Vec::new();
962+
963+
cx.simplify_match_pairs(&mut match_pairs, &mut bindings, &mut ascriptions);
964+
965+
FlatPat { span: pattern.span, match_pairs, bindings, ascriptions }
966+
}
967+
}
968+
941969
#[derive(Debug)]
942970
struct Candidate<'pat, 'tcx> {
943971
/// [`Span`] of the original pattern that gave rise to this candidate.
@@ -952,11 +980,11 @@ struct Candidate<'pat, 'tcx> {
952980
match_pairs: Vec<MatchPair<'pat, 'tcx>>,
953981

954982
/// ...these bindings established...
955-
// Invariant: not mutated outside `Candidate::new()`.
983+
// Invariant: not mutated after candidate creation.
956984
bindings: Vec<Binding<'tcx>>,
957985

958986
/// ...and these types asserted...
959-
// Invariant: not mutated outside `Candidate::new()`.
987+
// Invariant: not mutated after candidate creation.
960988
ascriptions: Vec<Ascription<'tcx>>,
961989

962990
/// ...and if this is non-empty, one of these subcandidates also has to match...
@@ -978,25 +1006,21 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
9781006
has_guard: bool,
9791007
cx: &mut Builder<'_, 'tcx>,
9801008
) -> Self {
981-
let mut candidate = Candidate {
982-
span: pattern.span,
1009+
Self::from_flat_pat(FlatPat::new(place, pattern, cx), has_guard)
1010+
}
1011+
1012+
fn from_flat_pat(flat_pat: FlatPat<'pat, 'tcx>, has_guard: bool) -> Self {
1013+
Candidate {
1014+
span: flat_pat.span,
1015+
match_pairs: flat_pat.match_pairs,
1016+
bindings: flat_pat.bindings,
1017+
ascriptions: flat_pat.ascriptions,
9831018
has_guard,
984-
match_pairs: vec![MatchPair::new(place, pattern, cx)],
985-
bindings: Vec::new(),
986-
ascriptions: Vec::new(),
9871019
subcandidates: Vec::new(),
9881020
otherwise_block: None,
9891021
pre_binding_block: None,
9901022
next_candidate_pre_binding_block: None,
991-
};
992-
993-
cx.simplify_match_pairs(
994-
&mut candidate.match_pairs,
995-
&mut candidate.bindings,
996-
&mut candidate.ascriptions,
997-
);
998-
999-
candidate
1023+
}
10001024
}
10011025

10021026
/// Visit the leaf candidates (those with no subcandidates) contained in
@@ -1059,7 +1083,7 @@ enum TestCase<'pat, 'tcx> {
10591083
Constant { value: mir::Const<'tcx> },
10601084
Range(&'pat PatRange<'tcx>),
10611085
Slice { len: usize, variable_length: bool },
1062-
Or,
1086+
Or { pats: Box<[FlatPat<'pat, 'tcx>]> },
10631087
}
10641088

10651089
#[derive(Debug, Clone)]
@@ -1205,19 +1229,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
12051229
///
12061230
/// Note how we test `x` twice. This is the tradeoff of backtracking automata: we prefer smaller
12071231
/// code size at the expense of non-optimal code paths.
1208-
#[instrument(skip(self, fake_borrows), level = "debug")]
1232+
#[instrument(skip(self), level = "debug")]
12091233
fn match_candidates<'pat>(
12101234
&mut self,
12111235
span: Span,
12121236
scrutinee_span: Span,
12131237
start_block: BasicBlock,
12141238
otherwise_block: BasicBlock,
12151239
candidates: &mut [&mut Candidate<'pat, 'tcx>],
1216-
fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>,
12171240
) {
12181241
let mut split_or_candidate = false;
12191242
for candidate in &mut *candidates {
1220-
if let [MatchPair { pattern: Pat { kind: PatKind::Or { pats }, .. }, place, .. }] =
1243+
if let [MatchPair { test_case: TestCase::Or { pats, .. }, .. }] =
12211244
&*candidate.match_pairs
12221245
{
12231246
// Split a candidate in which the only match-pair is an or-pattern into multiple
@@ -1229,8 +1252,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
12291252
// }
12301253
//
12311254
// only generates a single switch.
1232-
candidate.subcandidates =
1233-
self.create_or_subcandidates(place, pats, candidate.has_guard);
1255+
candidate.subcandidates = self.create_or_subcandidates(pats, candidate.has_guard);
12341256
candidate.match_pairs.pop();
12351257
split_or_candidate = true;
12361258
}
@@ -1251,7 +1273,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
12511273
start_block,
12521274
otherwise_block,
12531275
&mut *new_candidates,
1254-
fake_borrows,
12551276
);
12561277
} else {
12571278
self.match_simplified_candidates(
@@ -1260,7 +1281,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
12601281
start_block,
12611282
otherwise_block,
12621283
candidates,
1263-
fake_borrows,
12641284
);
12651285
}
12661286
});
@@ -1273,7 +1293,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
12731293
mut start_block: BasicBlock,
12741294
otherwise_block: BasicBlock,
12751295
candidates: &mut [&mut Candidate<'_, 'tcx>],
1276-
fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>,
12771296
) {
12781297
match candidates {
12791298
[] => {
@@ -1285,14 +1304,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
12851304
[first, remaining @ ..] if first.match_pairs.is_empty() => {
12861305
// The first candidate has satisfied all its match pairs; we link it up and continue
12871306
// with the remaining candidates.
1288-
start_block = self.select_matched_candidate(first, start_block, fake_borrows);
1307+
start_block = self.select_matched_candidate(first, start_block);
12891308
self.match_simplified_candidates(
12901309
span,
12911310
scrutinee_span,
12921311
start_block,
12931312
otherwise_block,
12941313
remaining,
1295-
fake_borrows,
12961314
)
12971315
}
12981316
candidates => {
@@ -1303,7 +1321,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
13031321
candidates,
13041322
start_block,
13051323
otherwise_block,
1306-
fake_borrows,
13071324
);
13081325
}
13091326
}
@@ -1338,43 +1355,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
13381355
&mut self,
13391356
candidate: &mut Candidate<'_, 'tcx>,
13401357
start_block: BasicBlock,
1341-
fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>,
13421358
) -> BasicBlock {
13431359
assert!(candidate.otherwise_block.is_none());
13441360
assert!(candidate.pre_binding_block.is_none());
13451361
assert!(candidate.subcandidates.is_empty());
13461362

1347-
if let Some(fake_borrows) = fake_borrows {
1348-
// Insert a borrows of prefixes of places that are bound and are
1349-
// behind a dereference projection.
1350-
//
1351-
// These borrows are taken to avoid situations like the following:
1352-
//
1353-
// match x[10] {
1354-
// _ if { x = &[0]; false } => (),
1355-
// y => (), // Out of bounds array access!
1356-
// }
1357-
//
1358-
// match *x {
1359-
// // y is bound by reference in the guard and then by copy in the
1360-
// // arm, so y is 2 in the arm!
1361-
// y if { y == 1 && (x = &2) == () } => y,
1362-
// _ => 3,
1363-
// }
1364-
for Binding { source, .. } in &candidate.bindings {
1365-
if let Some(i) =
1366-
source.projection.iter().rposition(|elem| elem == ProjectionElem::Deref)
1367-
{
1368-
let proj_base = &source.projection[..i];
1369-
1370-
fake_borrows.insert(Place {
1371-
local: source.local,
1372-
projection: self.tcx.mk_place_elems(proj_base),
1373-
});
1374-
}
1375-
}
1376-
}
1377-
13781363
candidate.pre_binding_block = Some(start_block);
13791364
let otherwise_block = self.cfg.start_new_block();
13801365
if candidate.has_guard {
@@ -1445,38 +1430,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
14451430
candidates: &mut [&mut Candidate<'_, 'tcx>],
14461431
start_block: BasicBlock,
14471432
otherwise_block: BasicBlock,
1448-
fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>,
14491433
) {
14501434
let (first_candidate, remaining_candidates) = candidates.split_first_mut().unwrap();
14511435
assert!(first_candidate.subcandidates.is_empty());
1452-
if !matches!(first_candidate.match_pairs[0].pattern.kind, PatKind::Or { .. }) {
1453-
self.test_candidates(
1454-
span,
1455-
scrutinee_span,
1456-
candidates,
1457-
start_block,
1458-
otherwise_block,
1459-
fake_borrows,
1460-
);
1436+
if !matches!(first_candidate.match_pairs[0].test_case, TestCase::Or { .. }) {
1437+
self.test_candidates(span, scrutinee_span, candidates, start_block, otherwise_block);
14611438
return;
14621439
}
14631440

14641441
let match_pairs = mem::take(&mut first_candidate.match_pairs);
14651442
let (first_match_pair, remaining_match_pairs) = match_pairs.split_first().unwrap();
1466-
let PatKind::Or { ref pats } = &first_match_pair.pattern.kind else { unreachable!() };
1443+
let TestCase::Or { ref pats } = &first_match_pair.test_case else { unreachable!() };
14671444

14681445
let remainder_start = self.cfg.start_new_block();
14691446
let or_span = first_match_pair.pattern.span;
14701447
// Test the alternatives of this or-pattern.
1471-
self.test_or_pattern(
1472-
first_candidate,
1473-
start_block,
1474-
remainder_start,
1475-
pats,
1476-
or_span,
1477-
&first_match_pair.place,
1478-
fake_borrows,
1479-
);
1448+
self.test_or_pattern(first_candidate, start_block, remainder_start, pats, or_span);
14801449

14811450
if !remaining_match_pairs.is_empty() {
14821451
// If more match pairs remain, test them after each subcandidate.
@@ -1497,7 +1466,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
14971466
&mut [leaf_candidate],
14981467
or_start,
14991468
or_otherwise,
1500-
fake_borrows,
15011469
);
15021470
});
15031471
}
@@ -1509,28 +1477,26 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
15091477
remainder_start,
15101478
otherwise_block,
15111479
remaining_candidates,
1512-
fake_borrows,
15131480
);
15141481
}
15151482

15161483
#[instrument(
1517-
skip(self, start_block, otherwise_block, or_span, place, fake_borrows, candidate, pats),
1484+
skip(self, start_block, otherwise_block, or_span, candidate, pats),
15181485
level = "debug"
15191486
)]
15201487
fn test_or_pattern<'pat>(
15211488
&mut self,
15221489
candidate: &mut Candidate<'pat, 'tcx>,
15231490
start_block: BasicBlock,
15241491
otherwise_block: BasicBlock,
1525-
pats: &'pat [Box<Pat<'tcx>>],
1492+
pats: &[FlatPat<'pat, 'tcx>],
15261493
or_span: Span,
1527-
place: &PlaceBuilder<'tcx>,
1528-
fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>,
15291494
) {
15301495
debug!("candidate={:#?}\npats={:#?}", candidate, pats);
15311496
let mut or_candidates: Vec<_> = pats
15321497
.iter()
1533-
.map(|pat| Candidate::new(place.clone(), pat, candidate.has_guard, self))
1498+
.cloned()
1499+
.map(|flat_pat| Candidate::from_flat_pat(flat_pat, candidate.has_guard))
15341500
.collect();
15351501
let mut or_candidate_refs: Vec<_> = or_candidates.iter_mut().collect();
15361502
self.match_candidates(
@@ -1539,7 +1505,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
15391505
start_block,
15401506
otherwise_block,
15411507
&mut or_candidate_refs,
1542-
fake_borrows,
15431508
);
15441509
candidate.subcandidates = or_candidates;
15451510
self.merge_trivial_subcandidates(candidate, self.source_info(or_span));
@@ -1599,7 +1564,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
15991564
fn pick_test(
16001565
&mut self,
16011566
candidates: &mut [&mut Candidate<'_, 'tcx>],
1602-
fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>,
16031567
) -> (PlaceBuilder<'tcx>, Test<'tcx>) {
16041568
// Extract the match-pair from the highest priority candidate
16051569
let match_pair = &candidates.first().unwrap().match_pairs[0];
@@ -1628,13 +1592,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
16281592
_ => {}
16291593
}
16301594

1631-
// Insert a Shallow borrow of any places that is switched on.
1632-
if let Some(fb) = fake_borrows
1633-
&& let Some(resolved_place) = match_place.try_to_place(self)
1634-
{
1635-
fb.insert(resolved_place);
1636-
}
1637-
16381595
(match_place, test)
16391596
}
16401597

@@ -1808,10 +1765,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
18081765
candidates: &'b mut [&'c mut Candidate<'pat, 'tcx>],
18091766
start_block: BasicBlock,
18101767
otherwise_block: BasicBlock,
1811-
fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>,
18121768
) {
18131769
// Extract the match-pair from the highest priority candidate and build a test from it.
1814-
let (match_place, test) = self.pick_test(candidates, fake_borrows);
1770+
let (match_place, test) = self.pick_test(candidates);
18151771

18161772
// For each of the N possible test outcomes, build the vector of candidates that applies if
18171773
// the test has that particular outcome.
@@ -1828,7 +1784,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
18281784
remainder_start,
18291785
otherwise_block,
18301786
remaining_candidates,
1831-
fake_borrows,
18321787
);
18331788
remainder_start
18341789
} else {
@@ -1850,7 +1805,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
18501805
candidate_start,
18511806
remainder_start,
18521807
&mut *candidates,
1853-
fake_borrows,
18541808
);
18551809
candidate_start
18561810
} else {

0 commit comments

Comments
 (0)