Skip to content

Commit 5a87e13

Browse files
authored
Rollup merge of #121393 - Nadrieril:match-lowering-testcase, r=matthewjasper
match lowering: Introduce a `TestCase` enum to replace most matching on `PatKind` Introduces `TestCase` that represents the specific outcome of a test. It complements `TestKind` which represents a test. In `MatchPair::new()` we select the appropriate `TestCase` for the pattern, and after that we almost never have to inspect the pattern directly during match lowering. Together with #120904, this makes `MatchPair` into a standalone abstraction that hides the details of `thir::Pat`. This will become even truer in the next PR where I make `TestCase` handle or patterns. This opens the door to a lot of future simplifications. r? `@matthewjasper`
2 parents 379ef9b + 0610f59 commit 5a87e13

File tree

4 files changed

+212
-260
lines changed

4 files changed

+212
-260
lines changed

compiler/rustc_mir_build/src/build/matches/mod.rs

+20-7
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use rustc_data_structures::{
1616
};
1717
use rustc_index::bit_set::BitSet;
1818
use rustc_middle::middle::region;
19-
use rustc_middle::mir::*;
19+
use rustc_middle::mir::{self, *};
2020
use rustc_middle::thir::{self, *};
2121
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty};
2222
use rustc_span::symbol::Symbol;
@@ -1052,18 +1052,31 @@ struct Ascription<'tcx> {
10521052
variance: ty::Variance,
10531053
}
10541054

1055+
#[derive(Debug, Clone)]
1056+
enum TestCase<'pat, 'tcx> {
1057+
Irrefutable { binding: Option<Binding<'tcx>>, ascription: Option<Ascription<'tcx>> },
1058+
Variant { adt_def: ty::AdtDef<'tcx>, variant_index: VariantIdx },
1059+
Constant { value: mir::Const<'tcx> },
1060+
Range(&'pat PatRange<'tcx>),
1061+
Slice { len: usize, variable_length: bool },
1062+
Or,
1063+
}
1064+
10551065
#[derive(Debug, Clone)]
10561066
pub(crate) struct MatchPair<'pat, 'tcx> {
1057-
// This place...
1067+
/// This place...
10581068
place: PlaceBuilder<'tcx>,
10591069

1060-
// ... must match this pattern.
1061-
// Invariant: after creation and simplification in `Candidate::new()`, all match pairs must be
1062-
// simplified, i.e. require a test.
1063-
pattern: &'pat Pat<'tcx>,
1070+
/// ... must pass this test...
1071+
// Invariant: after creation and simplification in `Candidate::new()`, this must not be
1072+
// `Irrefutable`.
1073+
test_case: TestCase<'pat, 'tcx>,
10641074

1065-
/// Precomputed sub-match pairs of `pattern`.
1075+
/// ... and these subpairs must match.
10661076
subpairs: Vec<Self>,
1077+
1078+
/// The pattern this was created from.
1079+
pattern: &'pat Pat<'tcx>,
10671080
}
10681081

10691082
/// See [`Test`] for more.

compiler/rustc_mir_build/src/build/matches/simplify.rs

+20-140
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,9 @@
1313
//! testing a value against a constant.
1414
1515
use crate::build::expr::as_place::PlaceBuilder;
16-
use crate::build::matches::{Ascription, Binding, Candidate, MatchPair};
16+
use crate::build::matches::{Ascription, Binding, Candidate, MatchPair, TestCase};
1717
use crate::build::Builder;
18-
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
19-
use rustc_middle::thir::{self, *};
20-
use rustc_middle::ty;
18+
use rustc_middle::thir::{Pat, PatKind};
2119

2220
use std::mem;
2321

@@ -62,13 +60,24 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
6260
let mut simplified_match_pairs = Vec::new();
6361
// Repeatedly simplify match pairs until we're left with only unsimplifiable ones.
6462
loop {
65-
for match_pair in mem::take(match_pairs) {
66-
if let Err(match_pair) = self.simplify_match_pair(
67-
match_pair,
68-
candidate_bindings,
69-
candidate_ascriptions,
70-
match_pairs,
71-
) {
63+
for mut match_pair in mem::take(match_pairs) {
64+
if let TestCase::Irrefutable { binding, ascription } = match_pair.test_case {
65+
if let Some(binding) = binding {
66+
candidate_bindings.push(binding);
67+
}
68+
if let Some(ascription) = ascription {
69+
candidate_ascriptions.push(ascription);
70+
}
71+
// Simplifiable pattern; we replace it with its subpairs and simplify further.
72+
match_pairs.append(&mut match_pair.subpairs);
73+
} else {
74+
// Unsimplifiable pattern; we recursively simplify its subpairs and don't
75+
// process it further.
76+
self.simplify_match_pairs(
77+
&mut match_pair.subpairs,
78+
candidate_bindings,
79+
candidate_ascriptions,
80+
);
7281
simplified_match_pairs.push(match_pair);
7382
}
7483
}
@@ -117,133 +126,4 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
117126
})
118127
.collect()
119128
}
120-
121-
/// Tries to simplify `match_pair`, returning `Ok(())` if successful. If successful, new match
122-
/// pairs and bindings will have been pushed into the respective `Vec`s. If no simplification is
123-
/// possible, `Err` is returned.
124-
fn simplify_match_pair<'pat>(
125-
&mut self,
126-
mut match_pair: MatchPair<'pat, 'tcx>,
127-
bindings: &mut Vec<Binding<'tcx>>,
128-
ascriptions: &mut Vec<Ascription<'tcx>>,
129-
match_pairs: &mut Vec<MatchPair<'pat, 'tcx>>,
130-
) -> Result<(), MatchPair<'pat, 'tcx>> {
131-
match match_pair.pattern.kind {
132-
PatKind::Leaf { .. }
133-
| PatKind::Deref { .. }
134-
| PatKind::Array { .. }
135-
| PatKind::Never
136-
| PatKind::Wild
137-
| PatKind::Error(_) => {}
138-
139-
PatKind::AscribeUserType {
140-
ascription: thir::Ascription { ref annotation, variance },
141-
..
142-
} => {
143-
// Apply the type ascription to the value at `match_pair.place`
144-
if let Some(source) = match_pair.place.try_to_place(self) {
145-
ascriptions.push(Ascription {
146-
annotation: annotation.clone(),
147-
source,
148-
variance,
149-
});
150-
}
151-
}
152-
153-
PatKind::Binding {
154-
name: _,
155-
mutability: _,
156-
mode,
157-
var,
158-
ty: _,
159-
subpattern: _,
160-
is_primary: _,
161-
} => {
162-
if let Some(source) = match_pair.place.try_to_place(self) {
163-
bindings.push(Binding {
164-
span: match_pair.pattern.span,
165-
source,
166-
var_id: var,
167-
binding_mode: mode,
168-
});
169-
}
170-
}
171-
172-
PatKind::InlineConstant { subpattern: ref pattern, def } => {
173-
// Apply a type ascription for the inline constant to the value at `match_pair.place`
174-
if let Some(source) = match_pair.place.try_to_place(self) {
175-
let span = match_pair.pattern.span;
176-
let parent_id = self.tcx.typeck_root_def_id(self.def_id.to_def_id());
177-
let args = ty::InlineConstArgs::new(
178-
self.tcx,
179-
ty::InlineConstArgsParts {
180-
parent_args: ty::GenericArgs::identity_for_item(self.tcx, parent_id),
181-
ty: self.infcx.next_ty_var(TypeVariableOrigin {
182-
kind: TypeVariableOriginKind::MiscVariable,
183-
span,
184-
}),
185-
},
186-
)
187-
.args;
188-
let user_ty =
189-
self.infcx.canonicalize_user_type_annotation(ty::UserType::TypeOf(
190-
def.to_def_id(),
191-
ty::UserArgs { args, user_self_ty: None },
192-
));
193-
let annotation = ty::CanonicalUserTypeAnnotation {
194-
inferred_ty: pattern.ty,
195-
span,
196-
user_ty: Box::new(user_ty),
197-
};
198-
ascriptions.push(Ascription {
199-
annotation,
200-
source,
201-
variance: ty::Contravariant,
202-
});
203-
}
204-
}
205-
206-
PatKind::Constant { .. } => {
207-
// FIXME normalize patterns when possible
208-
return Err(match_pair);
209-
}
210-
211-
PatKind::Range(ref range) => {
212-
if range.is_full_range(self.tcx) != Some(true) {
213-
return Err(match_pair);
214-
}
215-
}
216-
217-
PatKind::Slice { ref prefix, ref slice, ref suffix } => {
218-
if !(prefix.is_empty() && slice.is_some() && suffix.is_empty()) {
219-
self.simplify_match_pairs(&mut match_pair.subpairs, bindings, ascriptions);
220-
return Err(match_pair);
221-
}
222-
}
223-
224-
PatKind::Variant { adt_def, args, variant_index, subpatterns: _ } => {
225-
let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| {
226-
i == variant_index || {
227-
(self.tcx.features().exhaustive_patterns
228-
|| self.tcx.features().min_exhaustive_patterns)
229-
&& !v
230-
.inhabited_predicate(self.tcx, adt_def)
231-
.instantiate(self.tcx, args)
232-
.apply_ignore_module(self.tcx, self.param_env)
233-
}
234-
}) && (adt_def.did().is_local()
235-
|| !adt_def.is_variant_list_non_exhaustive());
236-
if !irrefutable {
237-
self.simplify_match_pairs(&mut match_pair.subpairs, bindings, ascriptions);
238-
return Err(match_pair);
239-
}
240-
}
241-
242-
PatKind::Or { .. } => return Err(match_pair),
243-
}
244-
245-
// Simplifiable pattern; we replace it with its subpairs.
246-
match_pairs.append(&mut match_pair.subpairs);
247-
Ok(())
248-
}
249129
}

0 commit comments

Comments
 (0)