Skip to content

Commit b2c933a

Browse files
authored
Rollup merge of #121715 - Nadrieril:testcase-or, r=matthewjasper
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 1c724ee + ae1e1bd commit b2c933a

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

+63-109
Original file line numberDiff line numberDiff line change
@@ -321,20 +321,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
321321
// The set of places that we are creating fake borrows of. If there are
322322
// no match guards then we don't need any fake borrows, so don't track
323323
// them.
324-
let mut fake_borrows = match_has_guard.then(FxIndexSet::default);
324+
let fake_borrows = match_has_guard
325+
.then(|| util::FakeBorrowCollector::collect_fake_borrows(self, candidates));
325326

326327
let otherwise_block = self.cfg.start_new_block();
327328

328329
// This will generate code to test scrutinee_place and
329330
// branch to the appropriate arm block
330-
self.match_candidates(
331-
match_start_span,
332-
scrutinee_span,
333-
block,
334-
otherwise_block,
335-
candidates,
336-
&mut fake_borrows,
337-
);
331+
self.match_candidates(match_start_span, scrutinee_span, block, otherwise_block, candidates);
338332

339333
// See the doc comment on `match_candidates` for why we may have an
340334
// otherwise block. Match checking will ensure this is actually
@@ -944,6 +938,40 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
944938
}
945939
}
946940

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

960988
/// ...these bindings established...
961-
// Invariant: not mutated outside `Candidate::new()`.
989+
// Invariant: not mutated after candidate creation.
962990
bindings: Vec<Binding<'tcx>>,
963991

964992
/// ...and these types asserted...
965-
// Invariant: not mutated outside `Candidate::new()`.
993+
// Invariant: not mutated after candidate creation.
966994
ascriptions: Vec<Ascription<'tcx>>,
967995

968996
/// ...and if this is non-empty, one of these subcandidates also has to match...
@@ -984,25 +1012,21 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
9841012
has_guard: bool,
9851013
cx: &mut Builder<'_, 'tcx>,
9861014
) -> Self {
987-
let mut candidate = Candidate {
988-
span: pattern.span,
1015+
Self::from_flat_pat(FlatPat::new(place, pattern, cx), has_guard)
1016+
}
1017+
1018+
fn from_flat_pat(flat_pat: FlatPat<'pat, 'tcx>, has_guard: bool) -> Self {
1019+
Candidate {
1020+
span: flat_pat.span,
1021+
match_pairs: flat_pat.match_pairs,
1022+
bindings: flat_pat.bindings,
1023+
ascriptions: flat_pat.ascriptions,
9891024
has_guard,
990-
match_pairs: vec![MatchPair::new(place, pattern, cx)],
991-
bindings: Vec::new(),
992-
ascriptions: Vec::new(),
9931025
subcandidates: Vec::new(),
9941026
otherwise_block: None,
9951027
pre_binding_block: None,
9961028
next_candidate_pre_binding_block: None,
997-
};
998-
999-
cx.simplify_match_pairs(
1000-
&mut candidate.match_pairs,
1001-
&mut candidate.bindings,
1002-
&mut candidate.ascriptions,
1003-
);
1004-
1005-
candidate
1029+
}
10061030
}
10071031

10081032
/// Visit the leaf candidates (those with no subcandidates) contained in
@@ -1065,7 +1089,7 @@ enum TestCase<'pat, 'tcx> {
10651089
Constant { value: mir::Const<'tcx> },
10661090
Range(&'pat PatRange<'tcx>),
10671091
Slice { len: usize, variable_length: bool },
1068-
Or,
1092+
Or { pats: Box<[FlatPat<'pat, 'tcx>]> },
10691093
}
10701094

10711095
#[derive(Debug, Clone)]
@@ -1208,19 +1232,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
12081232
///
12091233
/// Note how we test `x` twice. This is the tradeoff of backtracking automata: we prefer smaller
12101234
/// code size at the expense of non-optimal code paths.
1211-
#[instrument(skip(self, fake_borrows), level = "debug")]
1235+
#[instrument(skip(self), level = "debug")]
12121236
fn match_candidates<'pat>(
12131237
&mut self,
12141238
span: Span,
12151239
scrutinee_span: Span,
12161240
start_block: BasicBlock,
12171241
otherwise_block: BasicBlock,
12181242
candidates: &mut [&mut Candidate<'pat, 'tcx>],
1219-
fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>,
12201243
) {
12211244
let mut split_or_candidate = false;
12221245
for candidate in &mut *candidates {
1223-
if let [MatchPair { pattern: Pat { kind: PatKind::Or { pats }, .. }, place, .. }] =
1246+
if let [MatchPair { test_case: TestCase::Or { pats, .. }, .. }] =
12241247
&*candidate.match_pairs
12251248
{
12261249
// Split a candidate in which the only match-pair is an or-pattern into multiple
@@ -1232,8 +1255,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
12321255
// }
12331256
//
12341257
// only generates a single switch.
1235-
candidate.subcandidates =
1236-
self.create_or_subcandidates(place, pats, candidate.has_guard);
1258+
candidate.subcandidates = self.create_or_subcandidates(pats, candidate.has_guard);
12371259
candidate.match_pairs.pop();
12381260
split_or_candidate = true;
12391261
}
@@ -1254,7 +1276,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
12541276
start_block,
12551277
otherwise_block,
12561278
&mut *new_candidates,
1257-
fake_borrows,
12581279
);
12591280
} else {
12601281
self.match_simplified_candidates(
@@ -1263,7 +1284,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
12631284
start_block,
12641285
otherwise_block,
12651286
candidates,
1266-
fake_borrows,
12671287
);
12681288
}
12691289
});
@@ -1276,7 +1296,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
12761296
mut start_block: BasicBlock,
12771297
otherwise_block: BasicBlock,
12781298
candidates: &mut [&mut Candidate<'_, 'tcx>],
1279-
fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>,
12801299
) {
12811300
match candidates {
12821301
[] => {
@@ -1288,14 +1307,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
12881307
[first, remaining @ ..] if first.match_pairs.is_empty() => {
12891308
// The first candidate has satisfied all its match pairs; we link it up and continue
12901309
// with the remaining candidates.
1291-
start_block = self.select_matched_candidate(first, start_block, fake_borrows);
1310+
start_block = self.select_matched_candidate(first, start_block);
12921311
self.match_simplified_candidates(
12931312
span,
12941313
scrutinee_span,
12951314
start_block,
12961315
otherwise_block,
12971316
remaining,
1298-
fake_borrows,
12991317
)
13001318
}
13011319
candidates => {
@@ -1306,7 +1324,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
13061324
candidates,
13071325
start_block,
13081326
otherwise_block,
1309-
fake_borrows,
13101327
);
13111328
}
13121329
}
@@ -1341,43 +1358,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
13411358
&mut self,
13421359
candidate: &mut Candidate<'_, 'tcx>,
13431360
start_block: BasicBlock,
1344-
fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>,
13451361
) -> BasicBlock {
13461362
assert!(candidate.otherwise_block.is_none());
13471363
assert!(candidate.pre_binding_block.is_none());
13481364
assert!(candidate.subcandidates.is_empty());
13491365

1350-
if let Some(fake_borrows) = fake_borrows {
1351-
// Insert a borrows of prefixes of places that are bound and are
1352-
// behind a dereference projection.
1353-
//
1354-
// These borrows are taken to avoid situations like the following:
1355-
//
1356-
// match x[10] {
1357-
// _ if { x = &[0]; false } => (),
1358-
// y => (), // Out of bounds array access!
1359-
// }
1360-
//
1361-
// match *x {
1362-
// // y is bound by reference in the guard and then by copy in the
1363-
// // arm, so y is 2 in the arm!
1364-
// y if { y == 1 && (x = &2) == () } => y,
1365-
// _ => 3,
1366-
// }
1367-
for Binding { source, .. } in &candidate.bindings {
1368-
if let Some(i) =
1369-
source.projection.iter().rposition(|elem| elem == ProjectionElem::Deref)
1370-
{
1371-
let proj_base = &source.projection[..i];
1372-
1373-
fake_borrows.insert(Place {
1374-
local: source.local,
1375-
projection: self.tcx.mk_place_elems(proj_base),
1376-
});
1377-
}
1378-
}
1379-
}
1380-
13811366
candidate.pre_binding_block = Some(start_block);
13821367
let otherwise_block = self.cfg.start_new_block();
13831368
if candidate.has_guard {
@@ -1448,38 +1433,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
14481433
candidates: &mut [&mut Candidate<'_, 'tcx>],
14491434
start_block: BasicBlock,
14501435
otherwise_block: BasicBlock,
1451-
fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>,
14521436
) {
14531437
let (first_candidate, remaining_candidates) = candidates.split_first_mut().unwrap();
14541438
assert!(first_candidate.subcandidates.is_empty());
1455-
if !matches!(first_candidate.match_pairs[0].pattern.kind, PatKind::Or { .. }) {
1456-
self.test_candidates(
1457-
span,
1458-
scrutinee_span,
1459-
candidates,
1460-
start_block,
1461-
otherwise_block,
1462-
fake_borrows,
1463-
);
1439+
if !matches!(first_candidate.match_pairs[0].test_case, TestCase::Or { .. }) {
1440+
self.test_candidates(span, scrutinee_span, candidates, start_block, otherwise_block);
14641441
return;
14651442
}
14661443

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

14711448
let remainder_start = self.cfg.start_new_block();
14721449
let or_span = first_match_pair.pattern.span;
14731450
// Test the alternatives of this or-pattern.
1474-
self.test_or_pattern(
1475-
first_candidate,
1476-
start_block,
1477-
remainder_start,
1478-
pats,
1479-
or_span,
1480-
&first_match_pair.place,
1481-
fake_borrows,
1482-
);
1451+
self.test_or_pattern(first_candidate, start_block, remainder_start, pats, or_span);
14831452

14841453
if !remaining_match_pairs.is_empty() {
14851454
// If more match pairs remain, test them after each subcandidate.
@@ -1500,7 +1469,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
15001469
&mut [leaf_candidate],
15011470
or_start,
15021471
or_otherwise,
1503-
fake_borrows,
15041472
);
15051473
});
15061474
}
@@ -1512,28 +1480,26 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
15121480
remainder_start,
15131481
otherwise_block,
15141482
remaining_candidates,
1515-
fake_borrows,
15161483
);
15171484
}
15181485

15191486
#[instrument(
1520-
skip(self, start_block, otherwise_block, or_span, place, fake_borrows, candidate, pats),
1487+
skip(self, start_block, otherwise_block, or_span, candidate, pats),
15211488
level = "debug"
15221489
)]
15231490
fn test_or_pattern<'pat>(
15241491
&mut self,
15251492
candidate: &mut Candidate<'pat, 'tcx>,
15261493
start_block: BasicBlock,
15271494
otherwise_block: BasicBlock,
1528-
pats: &'pat [Box<Pat<'tcx>>],
1495+
pats: &[FlatPat<'pat, 'tcx>],
15291496
or_span: Span,
1530-
place: &PlaceBuilder<'tcx>,
1531-
fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>,
15321497
) {
15331498
debug!("candidate={:#?}\npats={:#?}", candidate, pats);
15341499
let mut or_candidates: Vec<_> = pats
15351500
.iter()
1536-
.map(|pat| Candidate::new(place.clone(), pat, candidate.has_guard, self))
1501+
.cloned()
1502+
.map(|flat_pat| Candidate::from_flat_pat(flat_pat, candidate.has_guard))
15371503
.collect();
15381504
let mut or_candidate_refs: Vec<_> = or_candidates.iter_mut().collect();
15391505
self.match_candidates(
@@ -1542,7 +1508,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
15421508
start_block,
15431509
otherwise_block,
15441510
&mut or_candidate_refs,
1545-
fake_borrows,
15461511
);
15471512
candidate.subcandidates = or_candidates;
15481513
self.merge_trivial_subcandidates(candidate, self.source_info(or_span));
@@ -1602,7 +1567,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
16021567
fn pick_test(
16031568
&mut self,
16041569
candidates: &mut [&mut Candidate<'_, 'tcx>],
1605-
fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>,
16061570
) -> (PlaceBuilder<'tcx>, Test<'tcx>) {
16071571
// Extract the match-pair from the highest priority candidate
16081572
let match_pair = &candidates.first().unwrap().match_pairs[0];
@@ -1631,13 +1595,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
16311595
_ => {}
16321596
}
16331597

1634-
// Insert a Shallow borrow of any places that is switched on.
1635-
if let Some(fb) = fake_borrows
1636-
&& let Some(resolved_place) = match_place.try_to_place(self)
1637-
{
1638-
fb.insert(resolved_place);
1639-
}
1640-
16411598
(match_place, test)
16421599
}
16431600

@@ -1811,10 +1768,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
18111768
candidates: &'b mut [&'c mut Candidate<'pat, 'tcx>],
18121769
start_block: BasicBlock,
18131770
otherwise_block: BasicBlock,
1814-
fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>,
18151771
) {
18161772
// Extract the match-pair from the highest priority candidate and build a test from it.
1817-
let (match_place, test) = self.pick_test(candidates, fake_borrows);
1773+
let (match_place, test) = self.pick_test(candidates);
18181774

18191775
// For each of the N possible test outcomes, build the vector of candidates that applies if
18201776
// the test has that particular outcome.
@@ -1831,7 +1787,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
18311787
remainder_start,
18321788
otherwise_block,
18331789
remaining_candidates,
1834-
fake_borrows,
18351790
);
18361791
remainder_start
18371792
} else {
@@ -1853,7 +1808,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
18531808
candidate_start,
18541809
remainder_start,
18551810
&mut *candidates,
1856-
fake_borrows,
18571811
);
18581812
candidate_start
18591813
} else {

0 commit comments

Comments
 (0)