about summary refs log tree commit diff
diff options
context:
space:
mode:
authorZalathar <Zalathar@users.noreply.github.com>2025-03-05 23:25:59 +1100
committerZalathar <Zalathar@users.noreply.github.com>2025-03-05 23:25:59 +1100
commitef442738386e8daf318f177bd6a551529e99b0da (patch)
tree44c4ffcd29b5d8911f99f5a80bafafceb0011c6d
parent281455add74530e23af760d60f6665a6901afc8b (diff)
downloadrust-ef442738386e8daf318f177bd6a551529e99b0da.tar.gz
rust-ef442738386e8daf318f177bd6a551529e99b0da.zip
Populate pattern bindings/ascriptions while building `MatchPairTree`
-rw-r--r--compiler/rustc_mir_build/src/builder/matches/match_pair.rs130
-rw-r--r--compiler/rustc_mir_build/src/builder/matches/mod.rs8
-rw-r--r--compiler/rustc_mir_build/src/builder/matches/simplify.rs8
3 files changed, 100 insertions, 46 deletions
diff --git a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs
index 7252dadc320..89d8189cee0 100644
--- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs
+++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs
@@ -6,7 +6,7 @@ use rustc_middle::ty::{self, Ty, TypeVisitableExt};
 
 use crate::builder::Builder;
 use crate::builder::expr::as_place::{PlaceBase, PlaceBuilder};
-use crate::builder::matches::{FlatPat, MatchPairTree, TestCase};
+use crate::builder::matches::{FlatPat, MatchPairTree, PatternExtraData, TestCase};
 
 impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// Builds and pushes [`MatchPairTree`] subtrees, one for each pattern in
@@ -17,12 +17,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     fn field_match_pairs(
         &mut self,
         match_pairs: &mut Vec<MatchPairTree<'tcx>>,
+        extra_data: &mut PatternExtraData<'tcx>,
         place: PlaceBuilder<'tcx>,
         subpatterns: &[FieldPat<'tcx>],
     ) {
         for fieldpat in subpatterns {
             let place = place.clone_project(PlaceElem::Field(fieldpat.field, fieldpat.pattern.ty));
-            MatchPairTree::for_pattern(place, &fieldpat.pattern, self, match_pairs);
+            MatchPairTree::for_pattern(place, &fieldpat.pattern, self, match_pairs, extra_data);
         }
     }
 
@@ -33,6 +34,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     fn prefix_slice_suffix(
         &mut self,
         match_pairs: &mut Vec<MatchPairTree<'tcx>>,
+        extra_data: &mut PatternExtraData<'tcx>,
         place: &PlaceBuilder<'tcx>,
         prefix: &[Pat<'tcx>],
         opt_slice: &Option<Box<Pat<'tcx>>>,
@@ -57,7 +59,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             let elem =
                 ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false };
             let place = place.clone_project(elem);
-            MatchPairTree::for_pattern(place, subpattern, self, match_pairs);
+            MatchPairTree::for_pattern(place, subpattern, self, match_pairs, extra_data)
         }
 
         if let Some(subslice_pat) = opt_slice {
@@ -67,7 +69,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 to: if exact_size { min_length - suffix_len } else { suffix_len },
                 from_end: !exact_size,
             });
-            MatchPairTree::for_pattern(subslice, subslice_pat, self, match_pairs);
+            MatchPairTree::for_pattern(subslice, subslice_pat, self, match_pairs, extra_data);
         }
 
         for (idx, subpattern) in suffix.iter().rev().enumerate() {
@@ -78,7 +80,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 from_end: !exact_size,
             };
             let place = place.clone_project(elem);
-            MatchPairTree::for_pattern(place, subpattern, self, match_pairs);
+            MatchPairTree::for_pattern(place, subpattern, self, match_pairs, extra_data)
         }
     }
 }
@@ -86,11 +88,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 impl<'tcx> MatchPairTree<'tcx> {
     /// Recursively builds a match pair tree for the given pattern and its
     /// subpatterns.
-    pub(in crate::builder) fn for_pattern(
+    pub(super) fn for_pattern(
         mut place_builder: PlaceBuilder<'tcx>,
         pattern: &Pat<'tcx>,
         cx: &mut Builder<'_, 'tcx>,
         match_pairs: &mut Vec<Self>, // Newly-created nodes are added to this vector
+        extra_data: &mut PatternExtraData<'tcx>, // Bindings/ascriptions are added here
     ) {
         // Force the place type to the pattern's type.
         // FIXME(oli-obk): can we use this to simplify slice/array pattern hacks?
@@ -113,7 +116,7 @@ impl<'tcx> MatchPairTree<'tcx> {
         }
 
         let place = place_builder.try_to_place(cx);
-        let default_irrefutable = || TestCase::Irrefutable { binding: None, ascription: None };
+        let default_irrefutable = || TestCase::Irrefutable {};
         let mut subpairs = Vec::new();
         let test_case = match pattern.kind {
             PatKind::Wild | PatKind::Error(_) => default_irrefutable(),
@@ -137,39 +140,77 @@ impl<'tcx> MatchPairTree<'tcx> {
                 ref subpattern,
                 ..
             } => {
+                MatchPairTree::for_pattern(
+                    place_builder,
+                    subpattern,
+                    cx,
+                    &mut subpairs,
+                    extra_data,
+                );
+
                 // Apply the type ascription to the value at `match_pair.place`
-                let ascription = place.map(|source| super::Ascription {
-                    annotation: annotation.clone(),
-                    source,
-                    variance,
-                });
-
-                MatchPairTree::for_pattern(place_builder, subpattern, cx, &mut subpairs);
-                TestCase::Irrefutable { ascription, binding: None }
+                if let Some(source) = place {
+                    let annotation = annotation.clone();
+                    extra_data.ascriptions.push(super::Ascription { source, annotation, variance });
+                }
+
+                default_irrefutable()
             }
 
             PatKind::Binding { mode, var, ref subpattern, .. } => {
-                let binding = place.map(|source| super::Binding {
-                    span: pattern.span,
-                    source,
-                    var_id: var,
-                    binding_mode: mode,
-                });
+                // In order to please the borrow checker, when lowering a pattern
+                // like `x @ subpat` we must establish any bindings in `subpat`
+                // before establishing the binding for `x`.
+                //
+                // For example (from #69971):
+                //
+                // ```ignore (illustrative)
+                // struct NonCopyStruct {
+                //     copy_field: u32,
+                // }
+                //
+                // fn foo1(x: NonCopyStruct) {
+                //     let y @ NonCopyStruct { copy_field: z } = x;
+                //     // the above should turn into
+                //     let z = x.copy_field;
+                //     let y = x;
+                // }
+                // ```
 
+                // First, recurse into the subpattern, if any.
                 if let Some(subpattern) = subpattern.as_ref() {
                     // this is the `x @ P` case; have to keep matching against `P` now
-                    MatchPairTree::for_pattern(place_builder, subpattern, cx, &mut subpairs);
+                    MatchPairTree::for_pattern(
+                        place_builder,
+                        subpattern,
+                        cx,
+                        &mut subpairs,
+                        extra_data,
+                    );
+                }
+
+                // Then push this binding, after any bindings in the subpattern.
+                if let Some(source) = place {
+                    extra_data.bindings.push(super::Binding {
+                        span: pattern.span,
+                        source,
+                        var_id: var,
+                        binding_mode: mode,
+                    });
                 }
-                TestCase::Irrefutable { ascription: None, binding }
+
+                default_irrefutable()
             }
 
             PatKind::ExpandedConstant { subpattern: ref pattern, def_id: _, is_inline: false } => {
-                MatchPairTree::for_pattern(place_builder, pattern, cx, &mut subpairs);
+                MatchPairTree::for_pattern(place_builder, pattern, cx, &mut subpairs, extra_data);
                 default_irrefutable()
             }
             PatKind::ExpandedConstant { subpattern: ref pattern, def_id, is_inline: true } => {
+                MatchPairTree::for_pattern(place_builder, pattern, cx, &mut subpairs, extra_data);
+
                 // Apply a type ascription for the inline constant to the value at `match_pair.place`
-                let ascription = place.map(|source| {
+                if let Some(source) = place {
                     let span = pattern.span;
                     let parent_id = cx.tcx.typeck_root_def_id(cx.def_id.to_def_id());
                     let args = ty::InlineConstArgs::new(
@@ -188,19 +229,33 @@ impl<'tcx> MatchPairTree<'tcx> {
                         span,
                         user_ty: Box::new(user_ty),
                     };
-                    super::Ascription { annotation, source, variance: ty::Contravariant }
-                });
+                    let variance = ty::Contravariant;
+                    extra_data.ascriptions.push(super::Ascription { annotation, source, variance });
+                }
 
-                MatchPairTree::for_pattern(place_builder, pattern, cx, &mut subpairs);
-                TestCase::Irrefutable { ascription, binding: None }
+                default_irrefutable()
             }
 
             PatKind::Array { ref prefix, ref slice, ref suffix } => {
-                cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix);
+                cx.prefix_slice_suffix(
+                    &mut subpairs,
+                    extra_data,
+                    &place_builder,
+                    prefix,
+                    slice,
+                    suffix,
+                );
                 default_irrefutable()
             }
             PatKind::Slice { ref prefix, ref slice, ref suffix } => {
-                cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix);
+                cx.prefix_slice_suffix(
+                    &mut subpairs,
+                    extra_data,
+                    &place_builder,
+                    prefix,
+                    slice,
+                    suffix,
+                );
 
                 if prefix.is_empty() && slice.is_some() && suffix.is_empty() {
                     default_irrefutable()
@@ -214,7 +269,7 @@ impl<'tcx> MatchPairTree<'tcx> {
 
             PatKind::Variant { adt_def, variant_index, args, ref subpatterns } => {
                 let downcast_place = place_builder.downcast(adt_def, variant_index); // `(x as Variant)`
-                cx.field_match_pairs(&mut subpairs, downcast_place, subpatterns);
+                cx.field_match_pairs(&mut subpairs, extra_data, downcast_place, subpatterns);
 
                 let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| {
                     i == variant_index
@@ -232,12 +287,18 @@ impl<'tcx> MatchPairTree<'tcx> {
             }
 
             PatKind::Leaf { ref subpatterns } => {
-                cx.field_match_pairs(&mut subpairs, place_builder, subpatterns);
+                cx.field_match_pairs(&mut subpairs, extra_data, place_builder, subpatterns);
                 default_irrefutable()
             }
 
             PatKind::Deref { ref subpattern } => {
-                MatchPairTree::for_pattern(place_builder.deref(), subpattern, cx, &mut subpairs);
+                MatchPairTree::for_pattern(
+                    place_builder.deref(),
+                    subpattern,
+                    cx,
+                    &mut subpairs,
+                    extra_data,
+                );
                 default_irrefutable()
             }
 
@@ -253,6 +314,7 @@ impl<'tcx> MatchPairTree<'tcx> {
                     subpattern,
                     cx,
                     &mut subpairs,
+                    extra_data,
                 );
                 TestCase::Deref { temp, mutability }
             }
diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs
index e41001193d5..8c8f4c3c92c 100644
--- a/compiler/rustc_mir_build/src/builder/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs
@@ -1008,17 +1008,15 @@ impl<'tcx> FlatPat<'tcx> {
     /// Creates a `FlatPat` containing a simplified [`MatchPairTree`] list/forest
     /// for the given pattern.
     fn new(place: PlaceBuilder<'tcx>, pattern: &Pat<'tcx>, cx: &mut Builder<'_, 'tcx>) -> Self {
-        // First, recursively build a tree of match pairs for the given pattern.
+        // Recursively build a tree of match pairs for the given pattern.
         let mut match_pairs = vec![];
-        MatchPairTree::for_pattern(place, pattern, cx, &mut match_pairs);
         let mut extra_data = PatternExtraData {
             span: pattern.span,
             bindings: Vec::new(),
             ascriptions: Vec::new(),
             is_never: pattern.is_never_pattern(),
         };
-        // Recursively remove irrefutable match pairs, while recording their
-        // bindings/ascriptions, and sort or-patterns after other match pairs.
+        MatchPairTree::for_pattern(place, pattern, cx, &mut match_pairs, &mut extra_data);
         cx.simplify_match_pairs(&mut match_pairs, &mut extra_data);
 
         Self { match_pairs, extra_data }
@@ -1238,7 +1236,7 @@ struct Ascription<'tcx> {
 ///   - See [`Builder::expand_and_match_or_candidates`].
 #[derive(Debug, Clone)]
 enum TestCase<'tcx> {
-    Irrefutable { binding: Option<Binding<'tcx>>, ascription: Option<Ascription<'tcx>> },
+    Irrefutable {},
     Variant { adt_def: ty::AdtDef<'tcx>, variant_index: VariantIdx },
     Constant { value: mir::Const<'tcx> },
     Range(Arc<PatRange<'tcx>>),
diff --git a/compiler/rustc_mir_build/src/builder/matches/simplify.rs b/compiler/rustc_mir_build/src/builder/matches/simplify.rs
index 15c860151dc..f4bcf62a4b1 100644
--- a/compiler/rustc_mir_build/src/builder/matches/simplify.rs
+++ b/compiler/rustc_mir_build/src/builder/matches/simplify.rs
@@ -47,13 +47,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         // match lowering forces us to lower bindings inside or-patterns last.
         for mut match_pair in mem::take(match_pairs) {
             self.simplify_match_pairs(&mut match_pair.subpairs, extra_data);
-            if let TestCase::Irrefutable { binding, ascription } = match_pair.test_case {
-                if let Some(binding) = binding {
-                    extra_data.bindings.push(binding);
-                }
-                if let Some(ascription) = ascription {
-                    extra_data.ascriptions.push(ascription);
-                }
+            if let TestCase::Irrefutable {} = match_pair.test_case {
                 // Simplifiable pattern; we replace it with its already simplified subpairs.
                 match_pairs.append(&mut match_pair.subpairs);
             } else {