Skip to content

Commit ea29d6a

Browse files
committed
We can traverse bindings before lower_match_tree now
1 parent d8a38b0 commit ea29d6a

File tree

2 files changed

+98
-50
lines changed

2 files changed

+98
-50
lines changed

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

Lines changed: 33 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use rustc_span::symbol::Symbol;
2121
use rustc_span::{BytePos, Pos, Span};
2222
use rustc_target::abi::VariantIdx;
2323
use tracing::{debug, instrument};
24+
use util::visit_bindings;
2425

2526
// helper functions, broken out by category:
2627
mod simplify;
@@ -725,55 +726,49 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
725726
set_match_place: bool,
726727
) -> BlockAnd<()> {
727728
let mut candidate = Candidate::new(initializer.clone(), irrefutable_pat, false, self);
728-
let fake_borrow_temps = self.lower_match_tree(
729-
block,
730-
irrefutable_pat.span,
731-
&initializer,
732-
irrefutable_pat.span,
733-
false,
734-
&mut [&mut candidate],
735-
);
736729

737730
// For matches and function arguments, the place that is being matched
738731
// can be set when creating the variables. But the place for
739732
// let PATTERN = ... might not even exist until we do the assignment.
740733
// so we set it here instead.
741734
if set_match_place {
742-
let mut next = Some(&candidate);
743-
while let Some(candidate_ref) = next.take() {
744-
for binding in &candidate_ref.extra_data.bindings {
735+
// `try_to_place` may fail if it is unable to resolve the given `PlaceBuilder` inside a
736+
// closure. In this case, we don't want to include a scrutinee place.
737+
// `scrutinee_place_builder` will fail for destructured assignments. This is because a
738+
// closure only captures the precise places that it will read and as a result a closure
739+
// may not capture the entire tuple/struct and rather have individual places that will
740+
// be read in the final MIR.
741+
// Example:
742+
// ```
743+
// let foo = (0, 1);
744+
// let c = || {
745+
// let (v1, v2) = foo;
746+
// };
747+
// ```
748+
if let Some(place) = initializer.try_to_place(self) {
749+
visit_bindings(&[&mut candidate], |binding: &Binding<'_>| {
745750
let local = self.var_local_id(binding.var_id, OutsideGuard);
746-
// `try_to_place` may fail if it is unable to resolve the given
747-
// `PlaceBuilder` inside a closure. In this case, we don't want to include
748-
// a scrutinee place. `scrutinee_place_builder` will fail for destructured
749-
// assignments. This is because a closure only captures the precise places
750-
// that it will read and as a result a closure may not capture the entire
751-
// tuple/struct and rather have individual places that will be read in the
752-
// final MIR.
753-
// Example:
754-
// ```
755-
// let foo = (0, 1);
756-
// let c = || {
757-
// let (v1, v2) = foo;
758-
// };
759-
// ```
760-
if let Some(place) = initializer.try_to_place(self) {
761-
let LocalInfo::User(BindingForm::Var(VarBindingForm {
762-
opt_match_place: Some((ref mut match_place, _)),
763-
..
764-
})) = **self.local_decls[local].local_info.as_mut().assert_crate_local()
765-
else {
766-
bug!("Let binding to non-user variable.")
767-
};
751+
if let LocalInfo::User(BindingForm::Var(VarBindingForm {
752+
opt_match_place: Some((ref mut match_place, _)),
753+
..
754+
})) = **self.local_decls[local].local_info.as_mut().assert_crate_local()
755+
{
768756
*match_place = Some(place);
769-
}
770-
}
771-
// All of the subcandidates should bind the same locals, so we
772-
// only visit the first one.
773-
next = candidate_ref.subcandidates.get(0)
757+
} else {
758+
bug!("Let binding to non-user variable.")
759+
};
760+
});
774761
}
775762
}
776763

764+
let fake_borrow_temps = self.lower_match_tree(
765+
block,
766+
irrefutable_pat.span,
767+
&initializer,
768+
irrefutable_pat.span,
769+
false,
770+
&mut [&mut candidate],
771+
);
777772
self.bind_pattern(
778773
self.source_info(irrefutable_pat.span),
779774
candidate,

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

Lines changed: 65 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::marker::PhantomData;
2+
13
use crate::build::expr::as_place::{PlaceBase, PlaceBuilder};
24
use crate::build::matches::{Binding, Candidate, FlatPat, MatchPair, TestCase};
35
use crate::build::Builder;
@@ -267,18 +269,6 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
267269
}
268270
}
269271

270-
pub(super) struct FakeBorrowCollector<'a, 'b, 'tcx> {
271-
cx: &'a mut Builder<'b, 'tcx>,
272-
/// Base of the scrutinee place. Used to distinguish bindings inside the scrutinee place from
273-
/// bindings inside deref patterns.
274-
scrutinee_base: PlaceBase,
275-
/// Store for each place the kind of borrow to take. In case of conflicts, we take the strongest
276-
/// borrow (i.e. Deep > Shallow).
277-
/// Invariant: for any place in `fake_borrows`, all the prefixes of this place that are
278-
/// dereferences are also borrowed with the same of stronger borrow kind.
279-
fake_borrows: FxIndexMap<Place<'tcx>, FakeBorrowKind>,
280-
}
281-
282272
/// Determine the set of places that have to be stable across match guards.
283273
///
284274
/// Returns a list of places that need a fake borrow along with a local to store it.
@@ -342,6 +332,18 @@ pub(super) fn collect_fake_borrows<'tcx>(
342332
.collect()
343333
}
344334

335+
pub(super) struct FakeBorrowCollector<'a, 'b, 'tcx> {
336+
cx: &'a mut Builder<'b, 'tcx>,
337+
/// Base of the scrutinee place. Used to distinguish bindings inside the scrutinee place from
338+
/// bindings inside deref patterns.
339+
scrutinee_base: PlaceBase,
340+
/// Store for each place the kind of borrow to take. In case of conflicts, we take the strongest
341+
/// borrow (i.e. Deep > Shallow).
342+
/// Invariant: for any place in `fake_borrows`, all the prefixes of this place that are
343+
/// dereferences are also borrowed with the same of stronger borrow kind.
344+
fake_borrows: FxIndexMap<Place<'tcx>, FakeBorrowKind>,
345+
}
346+
345347
impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> {
346348
// Fake borrow this place and its dereference prefixes.
347349
fn fake_borrow(&mut self, place: Place<'tcx>, kind: FakeBorrowKind) {
@@ -455,6 +457,57 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> {
455457
}
456458
}
457459

460+
/// Visit all the bindings of these candidates. Because or-alternatives bind the same variables, we
461+
/// only explore the first one of each or-pattern.
462+
pub(super) fn visit_bindings<'tcx>(
463+
candidates: &[&mut Candidate<'_, 'tcx>],
464+
f: impl FnMut(&Binding<'tcx>),
465+
) {
466+
let mut visitor = BindingsVisitor { f, phantom: PhantomData };
467+
for candidate in candidates.iter() {
468+
visitor.visit_candidate(candidate);
469+
}
470+
}
471+
472+
pub(super) struct BindingsVisitor<'tcx, F> {
473+
f: F,
474+
phantom: PhantomData<&'tcx ()>,
475+
}
476+
477+
impl<'tcx, F> BindingsVisitor<'tcx, F>
478+
where
479+
F: FnMut(&Binding<'tcx>),
480+
{
481+
fn visit_candidate(&mut self, candidate: &Candidate<'_, 'tcx>) {
482+
for binding in &candidate.extra_data.bindings {
483+
(self.f)(binding)
484+
}
485+
for match_pair in &candidate.match_pairs {
486+
self.visit_match_pair(match_pair);
487+
}
488+
}
489+
490+
fn visit_flat_pat(&mut self, flat_pat: &FlatPat<'_, 'tcx>) {
491+
for binding in &flat_pat.extra_data.bindings {
492+
(self.f)(binding)
493+
}
494+
for match_pair in &flat_pat.match_pairs {
495+
self.visit_match_pair(match_pair);
496+
}
497+
}
498+
499+
fn visit_match_pair(&mut self, match_pair: &MatchPair<'_, 'tcx>) {
500+
if let TestCase::Or { pats, .. } = &match_pair.test_case {
501+
// All the or-alternatives should bind the same locals, so we only visit the first one.
502+
self.visit_flat_pat(&pats[0])
503+
} else {
504+
for subpair in &match_pair.subpairs {
505+
self.visit_match_pair(subpair);
506+
}
507+
}
508+
}
509+
}
510+
458511
#[must_use]
459512
pub(crate) fn ref_pat_borrow_kind(ref_mutability: Mutability) -> BorrowKind {
460513
match ref_mutability {

0 commit comments

Comments
 (0)