Skip to content

Commit dfb5e1f

Browse files
NadrierilZalathar
authored andcommitted
We can traverse bindings before lower_match_tree now
1 parent fda509e commit dfb5e1f

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;
@@ -728,55 +729,49 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
728729
set_match_place: bool,
729730
) -> BlockAnd<()> {
730731
let mut candidate = Candidate::new(initializer.clone(), irrefutable_pat, false, self);
731-
let fake_borrow_temps = self.lower_match_tree(
732-
block,
733-
irrefutable_pat.span,
734-
&initializer,
735-
irrefutable_pat.span,
736-
false,
737-
&mut [&mut candidate],
738-
);
739732

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

767+
let fake_borrow_temps = self.lower_match_tree(
768+
block,
769+
irrefutable_pat.span,
770+
&initializer,
771+
irrefutable_pat.span,
772+
false,
773+
&mut [&mut candidate],
774+
);
780775
self.bind_pattern(
781776
self.source_info(irrefutable_pat.span),
782777
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;
@@ -269,18 +271,6 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
269271
}
270272
}
271273

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

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

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

0 commit comments

Comments
 (0)