diff options
| author | Zalathar <Zalathar@users.noreply.github.com> | 2025-03-05 23:25:59 +1100 |
|---|---|---|
| committer | Zalathar <Zalathar@users.noreply.github.com> | 2025-03-05 23:25:59 +1100 |
| commit | ef442738386e8daf318f177bd6a551529e99b0da (patch) | |
| tree | 44c4ffcd29b5d8911f99f5a80bafafceb0011c6d | |
| parent | 281455add74530e23af760d60f6665a6901afc8b (diff) | |
| download | rust-ef442738386e8daf318f177bd6a551529e99b0da.tar.gz rust-ef442738386e8daf318f177bd6a551529e99b0da.zip | |
Populate pattern bindings/ascriptions while building `MatchPairTree`
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 { |
