about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_middle/src/thir.rs4
-rw-r--r--compiler/rustc_mir_build/src/builder/block.rs46
-rw-r--r--compiler/rustc_mir_build/src/builder/matches/mod.rs65
-rw-r--r--tests/mir-opt/building/user_type_annotations.let_else.built.after.mir3
-rw-r--r--tests/mir-opt/building/user_type_annotations.let_else_bindless.built.after.mir3
-rw-r--r--tests/mir-opt/building/user_type_annotations.let_uninit.built.after.mir1
-rw-r--r--tests/mir-opt/building/user_type_annotations.let_uninit_bindless.built.after.mir1
7 files changed, 67 insertions, 56 deletions
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index f7b98d935d4..1056644b813 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -783,8 +783,12 @@ pub enum PatKind<'tcx> {
         var: LocalVarId,
         ty: Ty<'tcx>,
         subpattern: Option<Box<Pat<'tcx>>>,
+
         /// Is this the leftmost occurrence of the binding, i.e., is `var` the
         /// `HirId` of this pattern?
+        ///
+        /// (The same binding can occur multiple times in different branches of
+        /// an or-pattern, but only one of them will be primary.)
         is_primary: bool,
     },
 
diff --git a/compiler/rustc_mir_build/src/builder/block.rs b/compiler/rustc_mir_build/src/builder/block.rs
index 7c76e02fcef..a71196f79d7 100644
--- a/compiler/rustc_mir_build/src/builder/block.rs
+++ b/compiler/rustc_mir_build/src/builder/block.rs
@@ -199,19 +199,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                             None,
                             Some((Some(&destination), initializer_span)),
                         );
-                        this.visit_primary_bindings(
-                            pattern,
-                            UserTypeProjections::none(),
-                            &mut |this, _, _, node, span, _, _| {
-                                this.storage_live_binding(
-                                    block,
-                                    node,
-                                    span,
-                                    OutsideGuard,
-                                    ScheduleDrops::Yes,
-                                );
-                            },
-                        );
+                        this.visit_primary_bindings(pattern, &mut |this, node, span| {
+                            this.storage_live_binding(
+                                block,
+                                node,
+                                span,
+                                OutsideGuard,
+                                ScheduleDrops::Yes,
+                            );
+                        });
                         let else_block_span = this.thir[*else_block].span;
                         let (matching, failure) =
                             this.in_if_then_scope(last_remainder_scope, else_block_span, |this| {
@@ -295,20 +291,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         });
 
                         debug!("ast_block_stmts: pattern={:?}", pattern);
-                        this.visit_primary_bindings(
-                            pattern,
-                            UserTypeProjections::none(),
-                            &mut |this, _, _, node, span, _, _| {
-                                this.storage_live_binding(
-                                    block,
-                                    node,
-                                    span,
-                                    OutsideGuard,
-                                    ScheduleDrops::Yes,
-                                );
-                                this.schedule_drop_for_binding(node, span, OutsideGuard);
-                            },
-                        )
+                        this.visit_primary_bindings(pattern, &mut |this, node, span| {
+                            this.storage_live_binding(
+                                block,
+                                node,
+                                span,
+                                OutsideGuard,
+                                ScheduleDrops::Yes,
+                            );
+                            this.schedule_drop_for_binding(node, span, OutsideGuard);
+                        })
                     }
 
                     // Enter the visibility scope, after evaluating the initializer.
diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs
index 89faf705d19..60cd8a2c89c 100644
--- a/compiler/rustc_mir_build/src/builder/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs
@@ -755,7 +755,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         guard: Option<ExprId>,
         opt_match_place: Option<(Option<&Place<'tcx>>, Span)>,
     ) -> Option<SourceScope> {
-        self.visit_primary_bindings(
+        self.visit_primary_bindings_special(
             pattern,
             UserTypeProjections::none(),
             &mut |this, name, mode, var, span, ty, user_ty| {
@@ -846,12 +846,34 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         }
     }
 
-    /// Visit all of the primary bindings in a patterns, that is, visit the
-    /// leftmost occurrence of each variable bound in a pattern. A variable
-    /// will occur more than once in an or-pattern.
+    /// Visits all of the "primary" bindings in a pattern, i.e. the leftmost
+    /// occurrence of each variable bound by the pattern.
+    /// See [`PatKind::Binding::is_primary`] for more context.
+    ///
+    /// This variant provides only the limited subset of binding data needed
+    /// by its callers, and should be a "pure" visit without side-effects.
     pub(super) fn visit_primary_bindings(
         &mut self,
         pattern: &Pat<'tcx>,
+        f: &mut impl FnMut(&mut Self, LocalVarId, Span),
+    ) {
+        pattern.walk_always(|pat| {
+            if let PatKind::Binding { var, is_primary: true, .. } = pat.kind {
+                f(self, var, pat.span);
+            }
+        })
+    }
+
+    /// Visits all of the "primary" bindings in a pattern, while preparing
+    /// additional user-type-annotation data needed by `declare_bindings`.
+    ///
+    /// This also has the side-effect of pushing all user type annotations
+    /// onto `canonical_user_type_annotations`, so that they end up in MIR
+    /// even if they aren't associated with any bindings.
+    #[instrument(level = "debug", skip(self, f))]
+    fn visit_primary_bindings_special(
+        &mut self,
+        pattern: &Pat<'tcx>,
         pattern_user_ty: UserTypeProjections,
         f: &mut impl FnMut(
             &mut Self,
@@ -863,17 +885,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             UserTypeProjections,
         ),
     ) {
-        debug!(
-            "visit_primary_bindings: pattern={:?} pattern_user_ty={:?}",
-            pattern, pattern_user_ty
-        );
+        // Avoid having to write the full method name at each recursive call.
+        let visit_subpat = |this: &mut Self, subpat, user_tys, f: &mut _| {
+            this.visit_primary_bindings_special(subpat, user_tys, f)
+        };
+
         match pattern.kind {
             PatKind::Binding { name, mode, var, ty, ref subpattern, is_primary, .. } => {
                 if is_primary {
                     f(self, name, mode, var, pattern.span, ty, pattern_user_ty.clone());
                 }
                 if let Some(subpattern) = subpattern.as_ref() {
-                    self.visit_primary_bindings(subpattern, pattern_user_ty, f);
+                    visit_subpat(self, subpattern, pattern_user_ty, f);
                 }
             }
 
@@ -882,17 +905,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 let from = u64::try_from(prefix.len()).unwrap();
                 let to = u64::try_from(suffix.len()).unwrap();
                 for subpattern in prefix.iter() {
-                    self.visit_primary_bindings(subpattern, pattern_user_ty.clone().index(), f);
+                    visit_subpat(self, subpattern, pattern_user_ty.clone().index(), f);
                 }
                 if let Some(subpattern) = slice {
-                    self.visit_primary_bindings(
-                        subpattern,
-                        pattern_user_ty.clone().subslice(from, to),
-                        f,
-                    );
+                    visit_subpat(self, subpattern, pattern_user_ty.clone().subslice(from, to), f);
                 }
                 for subpattern in suffix.iter() {
-                    self.visit_primary_bindings(subpattern, pattern_user_ty.clone().index(), f);
+                    visit_subpat(self, subpattern, pattern_user_ty.clone().index(), f);
                 }
             }
 
@@ -903,11 +922,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             | PatKind::Error(_) => {}
 
             PatKind::Deref { ref subpattern } => {
-                self.visit_primary_bindings(subpattern, pattern_user_ty.deref(), f);
+                visit_subpat(self, subpattern, pattern_user_ty.deref(), f);
             }
 
             PatKind::DerefPattern { ref subpattern, .. } => {
-                self.visit_primary_bindings(subpattern, UserTypeProjections::none(), f);
+                visit_subpat(self, subpattern, UserTypeProjections::none(), f);
             }
 
             PatKind::AscribeUserType {
@@ -925,18 +944,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
                 let base_user_ty = self.canonical_user_type_annotations.push(annotation.clone());
                 let subpattern_user_ty = pattern_user_ty.push_user_type(base_user_ty);
-                self.visit_primary_bindings(subpattern, subpattern_user_ty, f)
+                visit_subpat(self, subpattern, subpattern_user_ty, f)
             }
 
             PatKind::ExpandedConstant { ref subpattern, .. } => {
-                self.visit_primary_bindings(subpattern, pattern_user_ty, f)
+                visit_subpat(self, subpattern, pattern_user_ty, f)
             }
 
             PatKind::Leaf { ref subpatterns } => {
                 for subpattern in subpatterns {
                     let subpattern_user_ty = pattern_user_ty.clone().leaf(subpattern.field);
                     debug!("visit_primary_bindings: subpattern_user_ty={:?}", subpattern_user_ty);
-                    self.visit_primary_bindings(&subpattern.pattern, subpattern_user_ty, f);
+                    visit_subpat(self, &subpattern.pattern, subpattern_user_ty, f);
                 }
             }
 
@@ -944,7 +963,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 for subpattern in subpatterns {
                     let subpattern_user_ty =
                         pattern_user_ty.clone().variant(adt_def, variant_index, subpattern.field);
-                    self.visit_primary_bindings(&subpattern.pattern, subpattern_user_ty, f);
+                    visit_subpat(self, &subpattern.pattern, subpattern_user_ty, f);
                 }
             }
             PatKind::Or { ref pats } => {
@@ -953,7 +972,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 // `let (x | y) = ...`, the primary binding of `y` occurs in
                 // the right subpattern
                 for subpattern in pats.iter() {
-                    self.visit_primary_bindings(subpattern, pattern_user_ty.clone(), f);
+                    visit_subpat(self, subpattern, pattern_user_ty.clone(), f);
                 }
             }
         }
diff --git a/tests/mir-opt/building/user_type_annotations.let_else.built.after.mir b/tests/mir-opt/building/user_type_annotations.let_else.built.after.mir
index 4029930c855..3a515787c10 100644
--- a/tests/mir-opt/building/user_type_annotations.let_else.built.after.mir
+++ b/tests/mir-opt/building/user_type_annotations.let_else.built.after.mir
@@ -3,7 +3,6 @@
 | User Type Annotations
 | 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)
 | 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)
-| 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)
 |
 fn let_else() -> () {
     let mut _0: ();
@@ -51,7 +50,7 @@ fn let_else() -> () {
     }
 
     bb4: {
-        AscribeUserType(_5, +, UserTypeProjection { base: UserType(2), projs: [] });
+        AscribeUserType(_5, +, UserTypeProjection { base: UserType(1), projs: [] });
         _2 = copy (_5.0: u32);
         _3 = copy (_5.1: u64);
         _4 = copy (_5.2: &char);
diff --git a/tests/mir-opt/building/user_type_annotations.let_else_bindless.built.after.mir b/tests/mir-opt/building/user_type_annotations.let_else_bindless.built.after.mir
index ffac242e54e..52a6d904d45 100644
--- a/tests/mir-opt/building/user_type_annotations.let_else_bindless.built.after.mir
+++ b/tests/mir-opt/building/user_type_annotations.let_else_bindless.built.after.mir
@@ -3,7 +3,6 @@
 | User Type Annotations
 | 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)
 | 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)
-| 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)
 |
 fn let_else_bindless() -> () {
     let mut _0: ();
@@ -42,7 +41,7 @@ fn let_else_bindless() -> () {
     }
 
     bb4: {
-        AscribeUserType(_2, +, UserTypeProjection { base: UserType(2), projs: [] });
+        AscribeUserType(_2, +, UserTypeProjection { base: UserType(1), projs: [] });
         StorageDead(_4);
         StorageDead(_2);
         _0 = const ();
diff --git a/tests/mir-opt/building/user_type_annotations.let_uninit.built.after.mir b/tests/mir-opt/building/user_type_annotations.let_uninit.built.after.mir
index d86cbc5b192..76b5938b87d 100644
--- a/tests/mir-opt/building/user_type_annotations.let_uninit.built.after.mir
+++ b/tests/mir-opt/building/user_type_annotations.let_uninit.built.after.mir
@@ -2,7 +2,6 @@
 
 | User Type Annotations
 | 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)
-| 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)
 |
 fn let_uninit() -> () {
     let mut _0: ();
diff --git a/tests/mir-opt/building/user_type_annotations.let_uninit_bindless.built.after.mir b/tests/mir-opt/building/user_type_annotations.let_uninit_bindless.built.after.mir
index a85bdacad23..0cd12558771 100644
--- a/tests/mir-opt/building/user_type_annotations.let_uninit_bindless.built.after.mir
+++ b/tests/mir-opt/building/user_type_annotations.let_uninit_bindless.built.after.mir
@@ -2,7 +2,6 @@
 
 | User Type Annotations
 | 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)
-| 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)
 |
 fn let_uninit_bindless() -> () {
     let mut _0: ();