Skip to content

Commit 194619d

Browse files
authored
Unrolled build for rust-lang#137875
Rollup merge of rust-lang#137875 - Zalathar:irrefutable, r=Nadrieril mir_build: Integrate "simplification" steps into match-pair-tree creation The “simplification” step helps to prepare THIR patterns for lowering into MIR, and originally dates back to the earliest days of MIR in the compiler. Over time, various intermediate data structures have been introduced (e.g. `MatchPair`, later renamed to `MatchPairTree`) that reduce the need for a separate simplification step, because some of the necessary simplifications can be built into the construction of those intermediate structures instead. This PR continues that process to its logical conclusion and removes the simplification step entirely, by integrating its remaining responsibilities into match-pair-tree creation: flattening “irrefutable” nodes, collecting bindings/ascriptions in flat lists, and sorting or-patterns after other subpatterns. This has a few immediate benefits: - We can remove `TestCase::Irrefutable`, which was not allowed to exist after simplification, and was much larger than other test-case variants. - We can make `MatchPairTree::place` non-optional, because only irrefutable nodes could fail to have a place. In the future, this should also help with some ideas I have for simplifying how `AscribeUserType` and `ExpandedConstant` nodes are handled, by representing them as side-data keyed by THIR pattern ID, so that they are no longer their own kinds of THIR pattern node.
2 parents 4559163 + e3e74bc commit 194619d

File tree

5 files changed

+168
-204
lines changed

5 files changed

+168
-204
lines changed

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

+141-76
Original file line numberDiff line numberDiff line change
@@ -6,27 +6,25 @@ 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> {
12-
/// Builds and returns [`MatchPairTree`] subtrees, one for each pattern in
12+
/// Builds and pushes [`MatchPairTree`] subtrees, one for each pattern in
1313
/// `subpatterns`, representing the fields of a [`PatKind::Variant`] or
1414
/// [`PatKind::Leaf`].
1515
///
1616
/// Used internally by [`MatchPairTree::for_pattern`].
1717
fn field_match_pairs(
1818
&mut self,
19+
match_pairs: &mut Vec<MatchPairTree<'tcx>>,
20+
extra_data: &mut PatternExtraData<'tcx>,
1921
place: PlaceBuilder<'tcx>,
2022
subpatterns: &[FieldPat<'tcx>],
21-
) -> Vec<MatchPairTree<'tcx>> {
22-
subpatterns
23-
.iter()
24-
.map(|fieldpat| {
25-
let place =
26-
place.clone_project(PlaceElem::Field(fieldpat.field, fieldpat.pattern.ty));
27-
MatchPairTree::for_pattern(place, &fieldpat.pattern, self)
28-
})
29-
.collect()
23+
) {
24+
for fieldpat in subpatterns {
25+
let place = place.clone_project(PlaceElem::Field(fieldpat.field, fieldpat.pattern.ty));
26+
MatchPairTree::for_pattern(place, &fieldpat.pattern, self, match_pairs, extra_data);
27+
}
3028
}
3129

3230
/// Builds [`MatchPairTree`] subtrees for the prefix/middle/suffix parts of an
@@ -36,6 +34,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
3634
fn prefix_slice_suffix(
3735
&mut self,
3836
match_pairs: &mut Vec<MatchPairTree<'tcx>>,
37+
extra_data: &mut PatternExtraData<'tcx>,
3938
place: &PlaceBuilder<'tcx>,
4039
prefix: &[Pat<'tcx>],
4140
opt_slice: &Option<Box<Pat<'tcx>>>,
@@ -56,11 +55,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
5655
((prefix.len() + suffix.len()).try_into().unwrap(), false)
5756
};
5857

59-
match_pairs.extend(prefix.iter().enumerate().map(|(idx, subpattern)| {
58+
for (idx, subpattern) in prefix.iter().enumerate() {
6059
let elem =
6160
ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false };
62-
MatchPairTree::for_pattern(place.clone_project(elem), subpattern, self)
63-
}));
61+
let place = place.clone_project(elem);
62+
MatchPairTree::for_pattern(place, subpattern, self, match_pairs, extra_data)
63+
}
6464

6565
if let Some(subslice_pat) = opt_slice {
6666
let suffix_len = suffix.len() as u64;
@@ -69,30 +69,32 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
6969
to: if exact_size { min_length - suffix_len } else { suffix_len },
7070
from_end: !exact_size,
7171
});
72-
match_pairs.push(MatchPairTree::for_pattern(subslice, subslice_pat, self));
72+
MatchPairTree::for_pattern(subslice, subslice_pat, self, match_pairs, extra_data);
7373
}
7474

75-
match_pairs.extend(suffix.iter().rev().enumerate().map(|(idx, subpattern)| {
75+
for (idx, subpattern) in suffix.iter().rev().enumerate() {
7676
let end_offset = (idx + 1) as u64;
7777
let elem = ProjectionElem::ConstantIndex {
7878
offset: if exact_size { min_length - end_offset } else { end_offset },
7979
min_length,
8080
from_end: !exact_size,
8181
};
8282
let place = place.clone_project(elem);
83-
MatchPairTree::for_pattern(place, subpattern, self)
84-
}));
83+
MatchPairTree::for_pattern(place, subpattern, self, match_pairs, extra_data)
84+
}
8585
}
8686
}
8787

8888
impl<'tcx> MatchPairTree<'tcx> {
8989
/// Recursively builds a match pair tree for the given pattern and its
9090
/// subpatterns.
91-
pub(in crate::builder) fn for_pattern(
91+
pub(super) fn for_pattern(
9292
mut place_builder: PlaceBuilder<'tcx>,
9393
pattern: &Pat<'tcx>,
9494
cx: &mut Builder<'_, 'tcx>,
95-
) -> MatchPairTree<'tcx> {
95+
match_pairs: &mut Vec<Self>, // Newly-created nodes are added to this vector
96+
extra_data: &mut PatternExtraData<'tcx>, // Bindings/ascriptions are added here
97+
) {
9698
// Force the place type to the pattern's type.
9799
// FIXME(oli-obk): can we use this to simplify slice/array pattern hacks?
98100
if let Some(resolved) = place_builder.resolve_upvar(cx) {
@@ -113,64 +115,102 @@ impl<'tcx> MatchPairTree<'tcx> {
113115
place_builder = place_builder.project(ProjectionElem::OpaqueCast(pattern.ty));
114116
}
115117

118+
// Place can be none if the pattern refers to a non-captured place in a closure.
116119
let place = place_builder.try_to_place(cx);
117-
let default_irrefutable = || TestCase::Irrefutable { binding: None, ascription: None };
118120
let mut subpairs = Vec::new();
119121
let test_case = match pattern.kind {
120-
PatKind::Wild | PatKind::Error(_) => default_irrefutable(),
122+
PatKind::Wild | PatKind::Error(_) => None,
121123

122-
PatKind::Or { ref pats } => TestCase::Or {
124+
PatKind::Or { ref pats } => Some(TestCase::Or {
123125
pats: pats.iter().map(|pat| FlatPat::new(place_builder.clone(), pat, cx)).collect(),
124-
},
126+
}),
125127

126128
PatKind::Range(ref range) => {
127129
if range.is_full_range(cx.tcx) == Some(true) {
128-
default_irrefutable()
130+
None
129131
} else {
130-
TestCase::Range(Arc::clone(range))
132+
Some(TestCase::Range(Arc::clone(range)))
131133
}
132134
}
133135

134-
PatKind::Constant { value } => TestCase::Constant { value },
136+
PatKind::Constant { value } => Some(TestCase::Constant { value }),
135137

136138
PatKind::AscribeUserType {
137139
ascription: Ascription { ref annotation, variance },
138140
ref subpattern,
139141
..
140142
} => {
143+
MatchPairTree::for_pattern(
144+
place_builder,
145+
subpattern,
146+
cx,
147+
&mut subpairs,
148+
extra_data,
149+
);
150+
141151
// Apply the type ascription to the value at `match_pair.place`
142-
let ascription = place.map(|source| super::Ascription {
143-
annotation: annotation.clone(),
144-
source,
145-
variance,
146-
});
147-
148-
subpairs.push(MatchPairTree::for_pattern(place_builder, subpattern, cx));
149-
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+
None
150158
}
151159

152160
PatKind::Binding { mode, var, ref subpattern, .. } => {
153-
let binding = place.map(|source| super::Binding {
154-
span: pattern.span,
155-
source,
156-
var_id: var,
157-
binding_mode: mode,
158-
});
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+
// ```
159179

180+
// First, recurse into the subpattern, if any.
160181
if let Some(subpattern) = subpattern.as_ref() {
161182
// this is the `x @ P` case; have to keep matching against `P` now
162-
subpairs.push(MatchPairTree::for_pattern(place_builder, subpattern, cx));
183+
MatchPairTree::for_pattern(
184+
place_builder,
185+
subpattern,
186+
cx,
187+
&mut subpairs,
188+
extra_data,
189+
);
163190
}
164-
TestCase::Irrefutable { ascription: None, binding }
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+
});
200+
}
201+
202+
None
165203
}
166204

167205
PatKind::ExpandedConstant { subpattern: ref pattern, def_id: _, is_inline: false } => {
168-
subpairs.push(MatchPairTree::for_pattern(place_builder, pattern, cx));
169-
default_irrefutable()
206+
MatchPairTree::for_pattern(place_builder, pattern, cx, &mut subpairs, extra_data);
207+
None
170208
}
171209
PatKind::ExpandedConstant { subpattern: ref pattern, def_id, is_inline: true } => {
210+
MatchPairTree::for_pattern(place_builder, pattern, cx, &mut subpairs, extra_data);
211+
172212
// Apply a type ascription for the inline constant to the value at `match_pair.place`
173-
let ascription = place.map(|source| {
213+
if let Some(source) = place {
174214
let span = pattern.span;
175215
let parent_id = cx.tcx.typeck_root_def_id(cx.def_id.to_def_id());
176216
let args = ty::InlineConstArgs::new(
@@ -189,33 +229,47 @@ impl<'tcx> MatchPairTree<'tcx> {
189229
span,
190230
user_ty: Box::new(user_ty),
191231
};
192-
super::Ascription { annotation, source, variance: ty::Contravariant }
193-
});
232+
let variance = ty::Contravariant;
233+
extra_data.ascriptions.push(super::Ascription { annotation, source, variance });
234+
}
194235

195-
subpairs.push(MatchPairTree::for_pattern(place_builder, pattern, cx));
196-
TestCase::Irrefutable { ascription, binding: None }
236+
None
197237
}
198238

199239
PatKind::Array { ref prefix, ref slice, ref suffix } => {
200-
cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix);
201-
default_irrefutable()
240+
cx.prefix_slice_suffix(
241+
&mut subpairs,
242+
extra_data,
243+
&place_builder,
244+
prefix,
245+
slice,
246+
suffix,
247+
);
248+
None
202249
}
203250
PatKind::Slice { ref prefix, ref slice, ref suffix } => {
204-
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+
);
205259

206260
if prefix.is_empty() && slice.is_some() && suffix.is_empty() {
207-
default_irrefutable()
261+
None
208262
} else {
209-
TestCase::Slice {
263+
Some(TestCase::Slice {
210264
len: prefix.len() + suffix.len(),
211265
variable_length: slice.is_some(),
212-
}
266+
})
213267
}
214268
}
215269

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

220274
let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| {
221275
i == variant_index
@@ -225,21 +279,23 @@ impl<'tcx> MatchPairTree<'tcx> {
225279
.apply_ignore_module(cx.tcx, cx.infcx.typing_env(cx.param_env))
226280
}) && (adt_def.did().is_local()
227281
|| !adt_def.is_variant_list_non_exhaustive());
228-
if irrefutable {
229-
default_irrefutable()
230-
} else {
231-
TestCase::Variant { adt_def, variant_index }
232-
}
282+
if irrefutable { None } else { Some(TestCase::Variant { adt_def, variant_index }) }
233283
}
234284

235285
PatKind::Leaf { ref subpatterns } => {
236-
subpairs = cx.field_match_pairs(place_builder, subpatterns);
237-
default_irrefutable()
286+
cx.field_match_pairs(&mut subpairs, extra_data, place_builder, subpatterns);
287+
None
238288
}
239289

240290
PatKind::Deref { ref subpattern } => {
241-
subpairs.push(MatchPairTree::for_pattern(place_builder.deref(), subpattern, cx));
242-
default_irrefutable()
291+
MatchPairTree::for_pattern(
292+
place_builder.deref(),
293+
subpattern,
294+
cx,
295+
&mut subpairs,
296+
extra_data,
297+
);
298+
None
243299
}
244300

245301
PatKind::DerefPattern { ref subpattern, mutability } => {
@@ -249,23 +305,32 @@ impl<'tcx> MatchPairTree<'tcx> {
249305
Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, subpattern.ty, mutability),
250306
pattern.span,
251307
);
252-
subpairs.push(MatchPairTree::for_pattern(
308+
MatchPairTree::for_pattern(
253309
PlaceBuilder::from(temp).deref(),
254310
subpattern,
255311
cx,
256-
));
257-
TestCase::Deref { temp, mutability }
312+
&mut subpairs,
313+
extra_data,
314+
);
315+
Some(TestCase::Deref { temp, mutability })
258316
}
259317

260-
PatKind::Never => TestCase::Never,
318+
PatKind::Never => Some(TestCase::Never),
261319
};
262320

263-
MatchPairTree {
264-
place,
265-
test_case,
266-
subpairs,
267-
pattern_ty: pattern.ty,
268-
pattern_span: pattern.span,
321+
if let Some(test_case) = test_case {
322+
// This pattern is refutable, so push a new match-pair node.
323+
match_pairs.push(MatchPairTree {
324+
place: place.expect("refutable patterns should always have a place to inspect"),
325+
test_case,
326+
subpairs,
327+
pattern_ty: pattern.ty,
328+
pattern_span: pattern.span,
329+
})
330+
} else {
331+
// This pattern is irrefutable, so it doesn't need its own match-pair node.
332+
// Just push its refutable subpatterns instead, if any.
333+
match_pairs.extend(subpairs);
269334
}
270335
}
271336
}

0 commit comments

Comments
 (0)