Skip to content

Commit ef44273

Browse files
committed
Populate pattern bindings/ascriptions while building MatchPairTree
1 parent 281455a commit ef44273

File tree

3 files changed

+100
-46
lines changed

3 files changed

+100
-46
lines changed

Diff for: compiler/rustc_mir_build/src/builder/matches/match_pair.rs

+96-34
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use rustc_middle::ty::{self, Ty, TypeVisitableExt};
66

77
use crate::builder::Builder;
88
use crate::builder::expr::as_place::{PlaceBase, PlaceBuilder};
9-
use crate::builder::matches::{FlatPat, MatchPairTree, TestCase};
9+
use crate::builder::matches::{FlatPat, MatchPairTree, PatternExtraData, TestCase};
1010

1111
impl<'a, 'tcx> Builder<'a, 'tcx> {
1212
/// Builds and pushes [`MatchPairTree`] subtrees, one for each pattern in
@@ -17,12 +17,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1717
fn field_match_pairs(
1818
&mut self,
1919
match_pairs: &mut Vec<MatchPairTree<'tcx>>,
20+
extra_data: &mut PatternExtraData<'tcx>,
2021
place: PlaceBuilder<'tcx>,
2122
subpatterns: &[FieldPat<'tcx>],
2223
) {
2324
for fieldpat in subpatterns {
2425
let place = place.clone_project(PlaceElem::Field(fieldpat.field, fieldpat.pattern.ty));
25-
MatchPairTree::for_pattern(place, &fieldpat.pattern, self, match_pairs);
26+
MatchPairTree::for_pattern(place, &fieldpat.pattern, self, match_pairs, extra_data);
2627
}
2728
}
2829

@@ -33,6 +34,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
3334
fn prefix_slice_suffix(
3435
&mut self,
3536
match_pairs: &mut Vec<MatchPairTree<'tcx>>,
37+
extra_data: &mut PatternExtraData<'tcx>,
3638
place: &PlaceBuilder<'tcx>,
3739
prefix: &[Pat<'tcx>],
3840
opt_slice: &Option<Box<Pat<'tcx>>>,
@@ -57,7 +59,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
5759
let elem =
5860
ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false };
5961
let place = place.clone_project(elem);
60-
MatchPairTree::for_pattern(place, subpattern, self, match_pairs);
62+
MatchPairTree::for_pattern(place, subpattern, self, match_pairs, extra_data)
6163
}
6264

6365
if let Some(subslice_pat) = opt_slice {
@@ -67,7 +69,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
6769
to: if exact_size { min_length - suffix_len } else { suffix_len },
6870
from_end: !exact_size,
6971
});
70-
MatchPairTree::for_pattern(subslice, subslice_pat, self, match_pairs);
72+
MatchPairTree::for_pattern(subslice, subslice_pat, self, match_pairs, extra_data);
7173
}
7274

7375
for (idx, subpattern) in suffix.iter().rev().enumerate() {
@@ -78,19 +80,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
7880
from_end: !exact_size,
7981
};
8082
let place = place.clone_project(elem);
81-
MatchPairTree::for_pattern(place, subpattern, self, match_pairs);
83+
MatchPairTree::for_pattern(place, subpattern, self, match_pairs, extra_data)
8284
}
8385
}
8486
}
8587

8688
impl<'tcx> MatchPairTree<'tcx> {
8789
/// Recursively builds a match pair tree for the given pattern and its
8890
/// subpatterns.
89-
pub(in crate::builder) fn for_pattern(
91+
pub(super) fn for_pattern(
9092
mut place_builder: PlaceBuilder<'tcx>,
9193
pattern: &Pat<'tcx>,
9294
cx: &mut Builder<'_, 'tcx>,
9395
match_pairs: &mut Vec<Self>, // Newly-created nodes are added to this vector
96+
extra_data: &mut PatternExtraData<'tcx>, // Bindings/ascriptions are added here
9497
) {
9598
// Force the place type to the pattern's type.
9699
// FIXME(oli-obk): can we use this to simplify slice/array pattern hacks?
@@ -113,7 +116,7 @@ impl<'tcx> MatchPairTree<'tcx> {
113116
}
114117

115118
let place = place_builder.try_to_place(cx);
116-
let default_irrefutable = || TestCase::Irrefutable { binding: None, ascription: None };
119+
let default_irrefutable = || TestCase::Irrefutable {};
117120
let mut subpairs = Vec::new();
118121
let test_case = match pattern.kind {
119122
PatKind::Wild | PatKind::Error(_) => default_irrefutable(),
@@ -137,39 +140,77 @@ impl<'tcx> MatchPairTree<'tcx> {
137140
ref subpattern,
138141
..
139142
} => {
143+
MatchPairTree::for_pattern(
144+
place_builder,
145+
subpattern,
146+
cx,
147+
&mut subpairs,
148+
extra_data,
149+
);
150+
140151
// Apply the type ascription to the value at `match_pair.place`
141-
let ascription = place.map(|source| super::Ascription {
142-
annotation: annotation.clone(),
143-
source,
144-
variance,
145-
});
146-
147-
MatchPairTree::for_pattern(place_builder, subpattern, cx, &mut subpairs);
148-
TestCase::Irrefutable { ascription, binding: None }
152+
if let Some(source) = place {
153+
let annotation = annotation.clone();
154+
extra_data.ascriptions.push(super::Ascription { source, annotation, variance });
155+
}
156+
157+
default_irrefutable()
149158
}
150159

151160
PatKind::Binding { mode, var, ref subpattern, .. } => {
152-
let binding = place.map(|source| super::Binding {
153-
span: pattern.span,
154-
source,
155-
var_id: var,
156-
binding_mode: mode,
157-
});
161+
// In order to please the borrow checker, when lowering a pattern
162+
// like `x @ subpat` we must establish any bindings in `subpat`
163+
// before establishing the binding for `x`.
164+
//
165+
// For example (from #69971):
166+
//
167+
// ```ignore (illustrative)
168+
// struct NonCopyStruct {
169+
// copy_field: u32,
170+
// }
171+
//
172+
// fn foo1(x: NonCopyStruct) {
173+
// let y @ NonCopyStruct { copy_field: z } = x;
174+
// // the above should turn into
175+
// let z = x.copy_field;
176+
// let y = x;
177+
// }
178+
// ```
158179

180+
// First, recurse into the subpattern, if any.
159181
if let Some(subpattern) = subpattern.as_ref() {
160182
// this is the `x @ P` case; have to keep matching against `P` now
161-
MatchPairTree::for_pattern(place_builder, subpattern, cx, &mut subpairs);
183+
MatchPairTree::for_pattern(
184+
place_builder,
185+
subpattern,
186+
cx,
187+
&mut subpairs,
188+
extra_data,
189+
);
190+
}
191+
192+
// Then push this binding, after any bindings in the subpattern.
193+
if let Some(source) = place {
194+
extra_data.bindings.push(super::Binding {
195+
span: pattern.span,
196+
source,
197+
var_id: var,
198+
binding_mode: mode,
199+
});
162200
}
163-
TestCase::Irrefutable { ascription: None, binding }
201+
202+
default_irrefutable()
164203
}
165204

166205
PatKind::ExpandedConstant { subpattern: ref pattern, def_id: _, is_inline: false } => {
167-
MatchPairTree::for_pattern(place_builder, pattern, cx, &mut subpairs);
206+
MatchPairTree::for_pattern(place_builder, pattern, cx, &mut subpairs, extra_data);
168207
default_irrefutable()
169208
}
170209
PatKind::ExpandedConstant { subpattern: ref pattern, def_id, is_inline: true } => {
210+
MatchPairTree::for_pattern(place_builder, pattern, cx, &mut subpairs, extra_data);
211+
171212
// Apply a type ascription for the inline constant to the value at `match_pair.place`
172-
let ascription = place.map(|source| {
213+
if let Some(source) = place {
173214
let span = pattern.span;
174215
let parent_id = cx.tcx.typeck_root_def_id(cx.def_id.to_def_id());
175216
let args = ty::InlineConstArgs::new(
@@ -188,19 +229,33 @@ impl<'tcx> MatchPairTree<'tcx> {
188229
span,
189230
user_ty: Box::new(user_ty),
190231
};
191-
super::Ascription { annotation, source, variance: ty::Contravariant }
192-
});
232+
let variance = ty::Contravariant;
233+
extra_data.ascriptions.push(super::Ascription { annotation, source, variance });
234+
}
193235

194-
MatchPairTree::for_pattern(place_builder, pattern, cx, &mut subpairs);
195-
TestCase::Irrefutable { ascription, binding: None }
236+
default_irrefutable()
196237
}
197238

198239
PatKind::Array { ref prefix, ref slice, ref suffix } => {
199-
cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix);
240+
cx.prefix_slice_suffix(
241+
&mut subpairs,
242+
extra_data,
243+
&place_builder,
244+
prefix,
245+
slice,
246+
suffix,
247+
);
200248
default_irrefutable()
201249
}
202250
PatKind::Slice { ref prefix, ref slice, ref suffix } => {
203-
cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix);
251+
cx.prefix_slice_suffix(
252+
&mut subpairs,
253+
extra_data,
254+
&place_builder,
255+
prefix,
256+
slice,
257+
suffix,
258+
);
204259

205260
if prefix.is_empty() && slice.is_some() && suffix.is_empty() {
206261
default_irrefutable()
@@ -214,7 +269,7 @@ impl<'tcx> MatchPairTree<'tcx> {
214269

215270
PatKind::Variant { adt_def, variant_index, args, ref subpatterns } => {
216271
let downcast_place = place_builder.downcast(adt_def, variant_index); // `(x as Variant)`
217-
cx.field_match_pairs(&mut subpairs, downcast_place, subpatterns);
272+
cx.field_match_pairs(&mut subpairs, extra_data, downcast_place, subpatterns);
218273

219274
let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| {
220275
i == variant_index
@@ -232,12 +287,18 @@ impl<'tcx> MatchPairTree<'tcx> {
232287
}
233288

234289
PatKind::Leaf { ref subpatterns } => {
235-
cx.field_match_pairs(&mut subpairs, place_builder, subpatterns);
290+
cx.field_match_pairs(&mut subpairs, extra_data, place_builder, subpatterns);
236291
default_irrefutable()
237292
}
238293

239294
PatKind::Deref { ref subpattern } => {
240-
MatchPairTree::for_pattern(place_builder.deref(), subpattern, cx, &mut subpairs);
295+
MatchPairTree::for_pattern(
296+
place_builder.deref(),
297+
subpattern,
298+
cx,
299+
&mut subpairs,
300+
extra_data,
301+
);
241302
default_irrefutable()
242303
}
243304

@@ -253,6 +314,7 @@ impl<'tcx> MatchPairTree<'tcx> {
253314
subpattern,
254315
cx,
255316
&mut subpairs,
317+
extra_data,
256318
);
257319
TestCase::Deref { temp, mutability }
258320
}

Diff for: compiler/rustc_mir_build/src/builder/matches/mod.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -1008,17 +1008,15 @@ impl<'tcx> FlatPat<'tcx> {
10081008
/// Creates a `FlatPat` containing a simplified [`MatchPairTree`] list/forest
10091009
/// for the given pattern.
10101010
fn new(place: PlaceBuilder<'tcx>, pattern: &Pat<'tcx>, cx: &mut Builder<'_, 'tcx>) -> Self {
1011-
// First, recursively build a tree of match pairs for the given pattern.
1011+
// Recursively build a tree of match pairs for the given pattern.
10121012
let mut match_pairs = vec![];
1013-
MatchPairTree::for_pattern(place, pattern, cx, &mut match_pairs);
10141013
let mut extra_data = PatternExtraData {
10151014
span: pattern.span,
10161015
bindings: Vec::new(),
10171016
ascriptions: Vec::new(),
10181017
is_never: pattern.is_never_pattern(),
10191018
};
1020-
// Recursively remove irrefutable match pairs, while recording their
1021-
// bindings/ascriptions, and sort or-patterns after other match pairs.
1019+
MatchPairTree::for_pattern(place, pattern, cx, &mut match_pairs, &mut extra_data);
10221020
cx.simplify_match_pairs(&mut match_pairs, &mut extra_data);
10231021

10241022
Self { match_pairs, extra_data }
@@ -1238,7 +1236,7 @@ struct Ascription<'tcx> {
12381236
/// - See [`Builder::expand_and_match_or_candidates`].
12391237
#[derive(Debug, Clone)]
12401238
enum TestCase<'tcx> {
1241-
Irrefutable { binding: Option<Binding<'tcx>>, ascription: Option<Ascription<'tcx>> },
1239+
Irrefutable {},
12421240
Variant { adt_def: ty::AdtDef<'tcx>, variant_index: VariantIdx },
12431241
Constant { value: mir::Const<'tcx> },
12441242
Range(Arc<PatRange<'tcx>>),

Diff for: compiler/rustc_mir_build/src/builder/matches/simplify.rs

+1-7
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
4747
// match lowering forces us to lower bindings inside or-patterns last.
4848
for mut match_pair in mem::take(match_pairs) {
4949
self.simplify_match_pairs(&mut match_pair.subpairs, extra_data);
50-
if let TestCase::Irrefutable { binding, ascription } = match_pair.test_case {
51-
if let Some(binding) = binding {
52-
extra_data.bindings.push(binding);
53-
}
54-
if let Some(ascription) = ascription {
55-
extra_data.ascriptions.push(ascription);
56-
}
50+
if let TestCase::Irrefutable {} = match_pair.test_case {
5751
// Simplifiable pattern; we replace it with its already simplified subpairs.
5852
match_pairs.append(&mut match_pair.subpairs);
5953
} else {

0 commit comments

Comments
 (0)