Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 62c2c6e

Browse files
committedJul 20, 2024·
Entirely hide Candidates from outside lower_match_tree
1 parent c9b8f30 commit 62c2c6e

File tree

2 files changed

+64
-38
lines changed

2 files changed

+64
-38
lines changed
 

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

+60-38
Original file line numberDiff line numberDiff line change
@@ -363,36 +363,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
363363
unpack!(block = self.lower_scrutinee(block, scrutinee_id, scrutinee_span));
364364

365365
let arms = arms.iter().map(|arm| &self.thir[*arm]);
366-
// Assemble the initial list of candidates. These top-level candidates are 1:1 with the
367-
// original match arms, but other parts of match lowering also introduce subcandidates (for
368-
// sub-or-patterns). So inside the algorithm, the candidates list may not correspond to
369-
// match arms directly.
370-
let candidates: Vec<_> = arms
366+
let match_start_span = span.shrink_to_lo().to(scrutinee_span);
367+
let patterns = arms
371368
.clone()
372369
.map(|arm| {
373-
let arm_has_guard = arm.guard.is_some();
374-
let arm_candidate =
375-
Candidate::new(scrutinee_place.clone(), &arm.pattern, arm_has_guard, self);
376-
arm_candidate
370+
let has_match_guard =
371+
if arm.guard.is_some() { HasMatchGuard::Yes } else { HasMatchGuard::No };
372+
(&*arm.pattern, has_match_guard)
377373
})
378374
.collect();
379-
380-
// The set of places that we are creating fake borrows of. If there are no match guards then
381-
// we don't need any fake borrows, so don't track them.
382-
let match_has_guard = candidates.iter().any(|candidate| candidate.has_guard);
383-
let fake_borrow_temps: Vec<(Place<'tcx>, Local, FakeBorrowKind)> = if match_has_guard {
384-
util::collect_fake_borrows(self, &candidates, scrutinee_span, scrutinee_place.base())
385-
} else {
386-
Vec::new()
387-
};
388-
389-
let match_start_span = span.shrink_to_lo().to(scrutinee_span);
390375
let built_tree = self.lower_match_tree(
391376
block,
392377
scrutinee_span,
393378
&scrutinee_place,
394379
match_start_span,
395-
candidates,
380+
patterns,
396381
false,
397382
);
398383

@@ -401,9 +386,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
401386
scrutinee_place,
402387
scrutinee_span,
403388
arms,
404-
built_tree.branches,
389+
built_tree,
405390
self.source_info(span),
406-
fake_borrow_temps,
407391
)
408392
}
409393

@@ -435,16 +419,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
435419
scrutinee_place_builder: PlaceBuilder<'tcx>,
436420
scrutinee_span: Span,
437421
arms: impl IntoIterator<Item = &'pat Arm<'tcx>>,
438-
lowered_branches: impl IntoIterator<Item = MatchTreeBranch<'tcx>>,
422+
built_match_tree: BuiltMatchTree<'tcx>,
439423
outer_source_info: SourceInfo,
440-
fake_borrow_temps: Vec<(Place<'tcx>, Local, FakeBorrowKind)>,
441424
) -> BlockAnd<()>
442425
where
443426
'tcx: 'pat,
444427
{
445428
let arm_end_blocks: Vec<BasicBlock> = arms
446429
.into_iter()
447-
.zip(lowered_branches)
430+
.zip(built_match_tree.branches)
448431
.map(|(arm, branch)| {
449432
debug!("lowering arm {:?}\ncorresponding branch = {:?}", arm, branch);
450433

@@ -480,7 +463,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
480463
let arm_block = this.bind_pattern(
481464
outer_source_info,
482465
branch,
483-
&fake_borrow_temps,
466+
&built_match_tree.fake_borrow_temps,
484467
scrutinee_span,
485468
Some((arm, match_scope)),
486469
EmitStorageLive::Yes,
@@ -695,13 +678,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
695678
initializer: PlaceBuilder<'tcx>,
696679
set_match_place: bool,
697680
) -> BlockAnd<()> {
698-
let candidate = Candidate::new(initializer.clone(), irrefutable_pat, false, self);
699681
let built_tree = self.lower_match_tree(
700682
block,
701683
irrefutable_pat.span,
702684
&initializer,
703685
irrefutable_pat.span,
704-
vec![candidate],
686+
vec![(irrefutable_pat, HasMatchGuard::No)],
705687
false,
706688
);
707689
let [branch] = built_tree.branches.try_into().unwrap();
@@ -1077,12 +1059,15 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
10771059
fn new(
10781060
place: PlaceBuilder<'tcx>,
10791061
pattern: &'pat Pat<'tcx>,
1080-
has_guard: bool,
1062+
has_guard: HasMatchGuard,
10811063
cx: &mut Builder<'_, 'tcx>,
10821064
) -> Self {
10831065
// Use `FlatPat` to build simplified match pairs, then immediately
10841066
// incorporate them into a new candidate.
1085-
Self::from_flat_pat(FlatPat::new(place, pattern, cx), has_guard)
1067+
Self::from_flat_pat(
1068+
FlatPat::new(place, pattern, cx),
1069+
matches!(has_guard, HasMatchGuard::Yes),
1070+
)
10861071
}
10871072

10881073
/// Incorporates an already-simplified [`FlatPat`] into a new candidate.
@@ -1337,6 +1322,10 @@ struct MatchTreeBranch<'tcx> {
13371322
struct BuiltMatchTree<'tcx> {
13381323
branches: Vec<MatchTreeBranch<'tcx>>,
13391324
otherwise_block: BasicBlock,
1325+
/// If any of the branches had a guard, we collect here the places and locals to fakely borrow
1326+
/// to ensure match guards can't modify the values as we match them. For more details, see
1327+
/// [`util::collect_fake_borrows`].
1328+
fake_borrow_temps: Vec<(Place<'tcx>, Local, FakeBorrowKind)>,
13401329
}
13411330

13421331
impl<'tcx> MatchTreeSubBranch<'tcx> {
@@ -1387,12 +1376,18 @@ impl<'tcx> MatchTreeBranch<'tcx> {
13871376
}
13881377
}
13891378

1379+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1380+
enum HasMatchGuard {
1381+
Yes,
1382+
No,
1383+
}
1384+
13901385
impl<'a, 'tcx> Builder<'a, 'tcx> {
13911386
/// The entrypoint of the matching algorithm. Create the decision tree for the match expression,
13921387
/// starting from `block`.
13931388
///
1394-
/// Modifies `candidates` to store the bindings and type ascriptions for
1395-
/// that candidate.
1389+
/// `patterns` is a list of patterns, one for each arm. The associated boolean indicates whether
1390+
/// the arm has a guard.
13961391
///
13971392
/// `refutable` indicates whether the candidate list is refutable (for `if let` and `let else`)
13981393
/// or not (for `let` and `match`). In the refutable case we return the block to which we branch
@@ -1403,9 +1398,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
14031398
scrutinee_span: Span,
14041399
scrutinee_place_builder: &PlaceBuilder<'tcx>,
14051400
match_start_span: Span,
1406-
mut candidates: Vec<Candidate<'pat, 'tcx>>,
1401+
patterns: Vec<(&'pat Pat<'tcx>, HasMatchGuard)>,
14071402
refutable: bool,
1408-
) -> BuiltMatchTree<'tcx> {
1403+
) -> BuiltMatchTree<'tcx>
1404+
where
1405+
'tcx: 'pat,
1406+
{
1407+
// Assemble the initial list of candidates. These top-level candidates are 1:1 with the
1408+
// input patterns, but other parts of match lowering also introduce subcandidates (for
1409+
// sub-or-patterns). So inside the algorithm, the candidates list may not correspond to
1410+
// match arms directly.
1411+
let mut candidates: Vec<Candidate<'_, '_>> = patterns
1412+
.into_iter()
1413+
.map(|(pat, has_guard)| {
1414+
Candidate::new(scrutinee_place_builder.clone(), pat, has_guard, self)
1415+
})
1416+
.collect();
1417+
1418+
let fake_borrow_temps = util::collect_fake_borrows(
1419+
self,
1420+
&candidates,
1421+
scrutinee_span,
1422+
scrutinee_place_builder.base(),
1423+
);
1424+
14091425
// This will generate code to test scrutinee_place and branch to the appropriate arm block.
14101426
// If none of the arms match, we branch to `otherwise_block`. When lowering a `match`
14111427
// expression, exhaustiveness checking ensures that this block is unreachable.
@@ -1484,6 +1500,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
14841500
BuiltMatchTree {
14851501
branches: candidates.into_iter().map(MatchTreeBranch::from_candidate).collect(),
14861502
otherwise_block,
1503+
fake_borrow_temps,
14871504
}
14881505
}
14891506

@@ -2167,9 +2184,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
21672184
) -> BlockAnd<()> {
21682185
let expr_span = self.thir[expr_id].span;
21692186
let scrutinee = unpack!(block = self.lower_scrutinee(block, expr_id, expr_span));
2170-
let candidate = Candidate::new(scrutinee.clone(), pat, false, self);
2171-
let built_tree =
2172-
self.lower_match_tree(block, expr_span, &scrutinee, pat.span, vec![candidate], true);
2187+
let built_tree = self.lower_match_tree(
2188+
block,
2189+
expr_span,
2190+
&scrutinee,
2191+
pat.span,
2192+
vec![(pat, HasMatchGuard::No)],
2193+
true,
2194+
);
21732195
let [branch] = built_tree.branches.try_into().unwrap();
21742196

21752197
self.break_for_else(built_tree.otherwise_block, self.source_info(expr_span));

‎compiler/rustc_mir_build/src/build/matches/util.rs

+4
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ pub(super) fn collect_fake_borrows<'tcx>(
7171
temp_span: Span,
7272
scrutinee_base: PlaceBase,
7373
) -> Vec<(Place<'tcx>, Local, FakeBorrowKind)> {
74+
if candidates.iter().all(|candidate| !candidate.has_guard) {
75+
// Fake borrows are only used when there is a guard.
76+
return Vec::new();
77+
}
7478
let mut collector =
7579
FakeBorrowCollector { cx, scrutinee_base, fake_borrows: FxIndexMap::default() };
7680
for candidate in candidates.iter() {

0 commit comments

Comments
 (0)
Please sign in to comment.