Skip to content

Commit f2e128f

Browse files
committed
Split visit_primary_bindings into two variants
The existing method does some non-obvious extra work to collect user types and build user-type projections, which is specifically needed by `declare_bindings` and not by the other two callers.
1 parent c29d537 commit f2e128f

7 files changed

+67
-56
lines changed

compiler/rustc_middle/src/thir.rs

+4
Original file line numberDiff line numberDiff line change
@@ -772,8 +772,12 @@ pub enum PatKind<'tcx> {
772772
var: LocalVarId,
773773
ty: Ty<'tcx>,
774774
subpattern: Option<Box<Pat<'tcx>>>,
775+
775776
/// Is this the leftmost occurrence of the binding, i.e., is `var` the
776777
/// `HirId` of this pattern?
778+
///
779+
/// (The same binding can occur multiple times in different branches of
780+
/// an or-pattern, but only one of them will be primary.)
777781
is_primary: bool,
778782
},
779783

compiler/rustc_mir_build/src/builder/block.rs

+19-27
Original file line numberDiff line numberDiff line change
@@ -199,19 +199,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
199199
None,
200200
Some((Some(&destination), initializer_span)),
201201
);
202-
this.visit_primary_bindings(
203-
pattern,
204-
UserTypeProjections::none(),
205-
&mut |this, _, _, node, span, _, _| {
206-
this.storage_live_binding(
207-
block,
208-
node,
209-
span,
210-
OutsideGuard,
211-
ScheduleDrops::Yes,
212-
);
213-
},
214-
);
202+
this.visit_primary_bindings(pattern, &mut |this, node, span| {
203+
this.storage_live_binding(
204+
block,
205+
node,
206+
span,
207+
OutsideGuard,
208+
ScheduleDrops::Yes,
209+
);
210+
});
215211
let else_block_span = this.thir[*else_block].span;
216212
let (matching, failure) =
217213
this.in_if_then_scope(last_remainder_scope, else_block_span, |this| {
@@ -295,20 +291,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
295291
});
296292

297293
debug!("ast_block_stmts: pattern={:?}", pattern);
298-
this.visit_primary_bindings(
299-
pattern,
300-
UserTypeProjections::none(),
301-
&mut |this, _, _, node, span, _, _| {
302-
this.storage_live_binding(
303-
block,
304-
node,
305-
span,
306-
OutsideGuard,
307-
ScheduleDrops::Yes,
308-
);
309-
this.schedule_drop_for_binding(node, span, OutsideGuard);
310-
},
311-
)
294+
this.visit_primary_bindings(pattern, &mut |this, node, span| {
295+
this.storage_live_binding(
296+
block,
297+
node,
298+
span,
299+
OutsideGuard,
300+
ScheduleDrops::Yes,
301+
);
302+
this.schedule_drop_for_binding(node, span, OutsideGuard);
303+
})
312304
}
313305

314306
// Enter the visibility scope, after evaluating the initializer.

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

+42-23
Original file line numberDiff line numberDiff line change
@@ -756,7 +756,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
756756
guard: Option<ExprId>,
757757
opt_match_place: Option<(Option<&Place<'tcx>>, Span)>,
758758
) -> Option<SourceScope> {
759-
self.visit_primary_bindings(
759+
self.visit_primary_bindings_special(
760760
pattern,
761761
UserTypeProjections::none(),
762762
&mut |this, name, mode, var, span, ty, user_ty| {
@@ -847,10 +847,32 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
847847
}
848848
}
849849

850-
/// Visit all of the primary bindings in a patterns, that is, visit the
851-
/// leftmost occurrence of each variable bound in a pattern. A variable
852-
/// will occur more than once in an or-pattern.
850+
/// Visits all of the "primary" bindings in a pattern, i.e. the leftmost
851+
/// occurrence of each variable bound by the pattern.
852+
/// See [`PatKind::Binding::is_primary`] for more context.
853+
///
854+
/// This variant provides only the limited subset of binding data needed
855+
/// by its callers, and should be a "pure" visit without side-effects.
853856
pub(super) fn visit_primary_bindings(
857+
&mut self,
858+
pattern: &Pat<'tcx>,
859+
f: &mut impl FnMut(&mut Self, LocalVarId, Span),
860+
) {
861+
pattern.walk_always(|pat| {
862+
if let PatKind::Binding { var, is_primary: true, .. } = pat.kind {
863+
f(self, var, pat.span);
864+
}
865+
})
866+
}
867+
868+
/// Visits all of the "primary" bindings in a pattern, while preparing
869+
/// additional user-type-annotation data needed by `declare_bindings`.
870+
///
871+
/// This also has the side-effect of pushing all user type annotations
872+
/// onto `canonical_user_type_annotations`, so that they end up in MIR
873+
/// even if they aren't associated with any bindings.
874+
#[instrument(level = "debug", skip(self, f))]
875+
fn visit_primary_bindings_special(
854876
&mut self,
855877
pattern: &Pat<'tcx>,
856878
pattern_user_ty: UserTypeProjections,
@@ -864,17 +886,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
864886
UserTypeProjections,
865887
),
866888
) {
867-
debug!(
868-
"visit_primary_bindings: pattern={:?} pattern_user_ty={:?}",
869-
pattern, pattern_user_ty
870-
);
889+
// Avoid having to write the full method name at each recursive call.
890+
let visit_subpat = |this: &mut Self, subpat, user_tys, f: &mut _| {
891+
this.visit_primary_bindings_special(subpat, user_tys, f)
892+
};
893+
871894
match pattern.kind {
872895
PatKind::Binding { name, mode, var, ty, ref subpattern, is_primary, .. } => {
873896
if is_primary {
874897
f(self, name, mode, var, pattern.span, ty, pattern_user_ty.clone());
875898
}
876899
if let Some(subpattern) = subpattern.as_ref() {
877-
self.visit_primary_bindings(subpattern, pattern_user_ty, f);
900+
visit_subpat(self, subpattern, pattern_user_ty, f);
878901
}
879902
}
880903

@@ -883,17 +906,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
883906
let from = u64::try_from(prefix.len()).unwrap();
884907
let to = u64::try_from(suffix.len()).unwrap();
885908
for subpattern in prefix.iter() {
886-
self.visit_primary_bindings(subpattern, pattern_user_ty.clone().index(), f);
909+
visit_subpat(self, subpattern, pattern_user_ty.clone().index(), f);
887910
}
888911
if let Some(subpattern) = slice {
889-
self.visit_primary_bindings(
890-
subpattern,
891-
pattern_user_ty.clone().subslice(from, to),
892-
f,
893-
);
912+
visit_subpat(self, subpattern, pattern_user_ty.clone().subslice(from, to), f);
894913
}
895914
for subpattern in suffix.iter() {
896-
self.visit_primary_bindings(subpattern, pattern_user_ty.clone().index(), f);
915+
visit_subpat(self, subpattern, pattern_user_ty.clone().index(), f);
897916
}
898917
}
899918

@@ -904,11 +923,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
904923
| PatKind::Error(_) => {}
905924

906925
PatKind::Deref { ref subpattern } => {
907-
self.visit_primary_bindings(subpattern, pattern_user_ty.deref(), f);
926+
visit_subpat(self, subpattern, pattern_user_ty.deref(), f);
908927
}
909928

910929
PatKind::DerefPattern { ref subpattern, .. } => {
911-
self.visit_primary_bindings(subpattern, UserTypeProjections::none(), f);
930+
visit_subpat(self, subpattern, UserTypeProjections::none(), f);
912931
}
913932

914933
PatKind::AscribeUserType {
@@ -926,26 +945,26 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
926945

927946
let base_user_ty = self.canonical_user_type_annotations.push(annotation.clone());
928947
let subpattern_user_ty = pattern_user_ty.push_user_type(base_user_ty);
929-
self.visit_primary_bindings(subpattern, subpattern_user_ty, f)
948+
visit_subpat(self, subpattern, subpattern_user_ty, f)
930949
}
931950

932951
PatKind::ExpandedConstant { ref subpattern, .. } => {
933-
self.visit_primary_bindings(subpattern, pattern_user_ty, f)
952+
visit_subpat(self, subpattern, pattern_user_ty, f)
934953
}
935954

936955
PatKind::Leaf { ref subpatterns } => {
937956
for subpattern in subpatterns {
938957
let subpattern_user_ty = pattern_user_ty.clone().leaf(subpattern.field);
939958
debug!("visit_primary_bindings: subpattern_user_ty={:?}", subpattern_user_ty);
940-
self.visit_primary_bindings(&subpattern.pattern, subpattern_user_ty, f);
959+
visit_subpat(self, &subpattern.pattern, subpattern_user_ty, f);
941960
}
942961
}
943962

944963
PatKind::Variant { adt_def, args: _, variant_index, ref subpatterns } => {
945964
for subpattern in subpatterns {
946965
let subpattern_user_ty =
947966
pattern_user_ty.clone().variant(adt_def, variant_index, subpattern.field);
948-
self.visit_primary_bindings(&subpattern.pattern, subpattern_user_ty, f);
967+
visit_subpat(self, &subpattern.pattern, subpattern_user_ty, f);
949968
}
950969
}
951970
PatKind::Or { ref pats } => {
@@ -954,7 +973,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
954973
// `let (x | y) = ...`, the primary binding of `y` occurs in
955974
// the right subpattern
956975
for subpattern in pats.iter() {
957-
self.visit_primary_bindings(subpattern, pattern_user_ty.clone(), f);
976+
visit_subpat(self, subpattern, pattern_user_ty.clone(), f);
958977
}
959978
}
960979
}

tests/mir-opt/building/user_type_annotations.let_else.built.after.mir

+1-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
| User Type Annotations
44
| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:35:20: 35:45, inferred_ty: (u32, u64, &char)
55
| 1: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:35:20: 35:45, inferred_ty: (u32, u64, &char)
6-
| 2: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:35:20: 35:45, inferred_ty: (u32, u64, &char)
76
|
87
fn let_else() -> () {
98
let mut _0: ();
@@ -51,7 +50,7 @@ fn let_else() -> () {
5150
}
5251

5352
bb4: {
54-
AscribeUserType(_5, +, UserTypeProjection { base: UserType(2), projs: [] });
53+
AscribeUserType(_5, +, UserTypeProjection { base: UserType(1), projs: [] });
5554
_2 = copy (_5.0: u32);
5655
_3 = copy (_5.1: u64);
5756
_4 = copy (_5.2: &char);

tests/mir-opt/building/user_type_annotations.let_else_bindless.built.after.mir

+1-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
| User Type Annotations
44
| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:40:20: 40:45, inferred_ty: (u32, u64, &char)
55
| 1: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:40:20: 40:45, inferred_ty: (u32, u64, &char)
6-
| 2: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:40:20: 40:45, inferred_ty: (u32, u64, &char)
76
|
87
fn let_else_bindless() -> () {
98
let mut _0: ();
@@ -42,7 +41,7 @@ fn let_else_bindless() -> () {
4241
}
4342

4443
bb4: {
45-
AscribeUserType(_2, +, UserTypeProjection { base: UserType(2), projs: [] });
44+
AscribeUserType(_2, +, UserTypeProjection { base: UserType(1), projs: [] });
4645
StorageDead(_4);
4746
StorageDead(_2);
4847
_0 = const ();

tests/mir-opt/building/user_type_annotations.let_uninit.built.after.mir

-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
| User Type Annotations
44
| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:15:20: 15:45, inferred_ty: (u32, u64, &char)
5-
| 1: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:15:20: 15:45, inferred_ty: (u32, u64, &char)
65
|
76
fn let_uninit() -> () {
87
let mut _0: ();

tests/mir-opt/building/user_type_annotations.let_uninit_bindless.built.after.mir

-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
| User Type Annotations
44
| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:20:20: 20:45, inferred_ty: (u32, u64, &char)
5-
| 1: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:20:20: 20:45, inferred_ty: (u32, u64, &char)
65
|
76
fn let_uninit_bindless() -> () {
87
let mut _0: ();

0 commit comments

Comments
 (0)