Skip to content

Commit 54fa702

Browse files
committed
Unify the paths through is_useful
1 parent c96bd28 commit 54fa702

File tree

1 file changed

+53
-103
lines changed
  • compiler/rustc_mir_build/src/thir/pattern

1 file changed

+53
-103
lines changed

compiler/rustc_mir_build/src/thir/pattern/_match.rs

Lines changed: 53 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,6 @@
181181
//! we ignore all the patterns in the first column of `P` that involve other constructors.
182182
//! This is where `S(c, P)` comes in:
183183
//! `U(P, p) := U(S(c, P), S(c, p))`
184-
//! This special case is handled in `is_useful_specialized`.
185184
//!
186185
//! For example, if `P` is:
187186
//!
@@ -1116,8 +1115,8 @@ impl<'tcx> Constructor<'tcx> {
11161115
}
11171116
}
11181117

1119-
/// Some constructors (namely IntRange and Slice) actually stand for a set of actual
1120-
/// constructors (integers and fixed-sized slices). When specializing for these
1118+
/// Some constructors (namely Wildcard, IntRange and Slice) actually stand for a set of actual
1119+
/// constructors (like variants, integers or fixed-sized slices). When specializing for these
11211120
/// constructors, we want to be specialising for the actual underlying constructors.
11221121
/// Naively, we would simply return the list of constructors they correspond to. We instead are
11231122
/// more clever: if there are constructors that we know will behave the same wrt the current
@@ -1136,6 +1135,7 @@ impl<'tcx> Constructor<'tcx> {
11361135
debug!("Constructor::split({:#?}, {:#?})", self, pcx.matrix);
11371136

11381137
match self {
1138+
Wildcard => Constructor::split_wildcard(pcx),
11391139
// Fast-track if the range is trivial. In particular, we don't do the overlapping
11401140
// ranges check.
11411141
IntRange(ctor_range)
@@ -1149,6 +1149,30 @@ impl<'tcx> Constructor<'tcx> {
11491149
}
11501150
}
11511151

1152+
/// For wildcards, there are two groups of constructors: there are the constructors actually
1153+
/// present in the matrix (`head_ctors`), and the constructors not present (`missing_ctors`).
1154+
/// Two constructors that are not in the matrix will either both be catched (by a wildcard), or
1155+
/// both not be catched. Therefore we can keep the missing constructors grouped together.
1156+
fn split_wildcard<'p>(pcx: PatCtxt<'_, 'p, 'tcx>) -> SmallVec<[Self; 1]> {
1157+
// Missing constructors are those that are not matched by any non-wildcard patterns in the
1158+
// current column. We only fully construct them on-demand, because they're rarely used and
1159+
// can be big.
1160+
let missing_ctors = MissingConstructors::new(pcx);
1161+
1162+
if missing_ctors.is_empty() {
1163+
// All the constructors are present in the matrix, so we just go through them all.
1164+
// We must also split them first.
1165+
// Since `all_ctors` never contains wildcards, this won't recurse more than once.
1166+
let (all_ctors, _) = missing_ctors.into_inner();
1167+
all_ctors.into_iter().flat_map(|ctor| ctor.split(pcx, None)).collect()
1168+
} else {
1169+
// Some constructors are missing, thus we can specialize with the wildcard constructor,
1170+
// which will stand for those constructors that are missing, and behaves like any of
1171+
// them.
1172+
smallvec![Wildcard]
1173+
}
1174+
}
1175+
11521176
/// Returns whether `self` is covered by `other`, ie whether `self` is a subset of `other`. For
11531177
/// the simple cases, this is simply checking for equality. For the "grouped" constructors,
11541178
/// this checks for inclusion.
@@ -1617,8 +1641,8 @@ impl<'tcx> Usefulness<'tcx> {
16171641
match self {
16181642
UsefulWithWitness(witnesses) => {
16191643
let new_witnesses = if ctor.is_wildcard() {
1620-
let missing_ctors = MissingConstructors::new(pcx, is_top_level);
1621-
let new_patterns = missing_ctors.report_patterns(pcx);
1644+
let missing_ctors = MissingConstructors::new(pcx);
1645+
let new_patterns = missing_ctors.report_patterns(pcx, is_top_level);
16221646
witnesses
16231647
.into_iter()
16241648
.flat_map(|witness| {
@@ -2217,16 +2241,15 @@ impl<'tcx> std::cmp::PartialEq for IntRange<'tcx> {
22172241
struct MissingConstructors<'tcx> {
22182242
all_ctors: Vec<Constructor<'tcx>>,
22192243
used_ctors: Vec<Constructor<'tcx>>,
2220-
is_top_level: bool,
22212244
}
22222245

22232246
impl<'tcx> MissingConstructors<'tcx> {
2224-
fn new<'p>(pcx: PatCtxt<'_, 'p, 'tcx>, is_top_level: bool) -> Self {
2247+
fn new<'p>(pcx: PatCtxt<'_, 'p, 'tcx>) -> Self {
22252248
let used_ctors: Vec<Constructor<'_>> =
22262249
pcx.matrix.head_ctors(pcx.cx).cloned().filter(|c| !c.is_wildcard()).collect();
22272250
let all_ctors = all_constructors(pcx);
22282251

2229-
MissingConstructors { all_ctors, used_ctors, is_top_level }
2252+
MissingConstructors { all_ctors, used_ctors }
22302253
}
22312254

22322255
fn into_inner(self) -> (Vec<Constructor<'tcx>>, Vec<Constructor<'tcx>>) {
@@ -2244,7 +2267,11 @@ impl<'tcx> MissingConstructors<'tcx> {
22442267

22452268
/// List the patterns corresponding to the missing constructors. In some cases, instead of
22462269
/// listing all constructors of a given type, we prefer to simply report a wildcard.
2247-
fn report_patterns<'p>(&self, pcx: PatCtxt<'_, 'p, 'tcx>) -> SmallVec<[Pat<'tcx>; 1]> {
2270+
fn report_patterns<'p>(
2271+
&self,
2272+
pcx: PatCtxt<'_, 'p, 'tcx>,
2273+
is_top_level: bool,
2274+
) -> SmallVec<[Pat<'tcx>; 1]> {
22482275
// There are 2 ways we can report a witness here.
22492276
// Commonly, we can report all the "free"
22502277
// constructors as witnesses, e.g., if we have:
@@ -2272,7 +2299,7 @@ impl<'tcx> MissingConstructors<'tcx> {
22722299
// `used_ctors` is empty.
22732300
// The exception is: if we are at the top-level, for example in an empty match, we
22742301
// sometimes prefer reporting the list of constructors instead of just `_`.
2275-
let report_when_all_missing = self.is_top_level && !IntRange::is_integral(pcx.ty);
2302+
let report_when_all_missing = is_top_level && !IntRange::is_integral(pcx.ty);
22762303
if self.used_ctors.is_empty() && !report_when_all_missing {
22772304
// All constructors are unused. Report only a wildcard
22782305
// rather than each individual constructor.
@@ -2407,103 +2434,26 @@ crate fn is_useful<'p, 'tcx>(
24072434

24082435
debug!("is_useful_expand_first_col: ty={:#?}, expanding {:#?}", pcx.ty, v.head());
24092436

2410-
let constructor = v.head_ctor(cx);
2411-
let ret = if !constructor.is_wildcard() {
2412-
debug!("is_useful - expanding constructor: {:#?}", constructor);
2413-
constructor
2414-
.split(pcx, Some(hir_id))
2415-
.into_iter()
2416-
.map(|c| {
2417-
is_useful_specialized(
2418-
pcx,
2419-
v,
2420-
&c,
2421-
witness_preference,
2422-
hir_id,
2423-
is_under_guard,
2424-
is_top_level,
2425-
)
2426-
})
2427-
.find(|result| result.is_useful())
2428-
.unwrap_or(NotUseful)
2429-
} else {
2430-
debug!("is_useful - expanding wildcard");
2431-
2432-
// `missing_ctors` is the set of constructors from the same type as the
2433-
// first column of `matrix` that are matched only by wildcard patterns
2434-
// from the first column.
2435-
//
2436-
// Therefore, if there is some pattern that is unmatched by `matrix`,
2437-
// it will still be unmatched if the first constructor is replaced by
2438-
// any of the constructors in `missing_ctors`
2439-
2440-
// Missing constructors are those that are not matched by any non-wildcard patterns in the
2441-
// current column. We only fully construct them on-demand, because they're rarely used and
2442-
// can be big.
2443-
let missing_ctors = MissingConstructors::new(pcx, is_top_level);
2444-
2445-
debug!("is_useful_missing_ctors.empty()={:#?}", missing_ctors.is_empty(),);
2446-
2447-
if missing_ctors.is_empty() {
2448-
let (all_ctors, _) = missing_ctors.into_inner();
2449-
all_ctors
2450-
.into_iter()
2451-
.flat_map(|ctor| ctor.split(pcx, None))
2452-
.map(|c| {
2453-
is_useful_specialized(
2454-
pcx,
2455-
v,
2456-
&c,
2457-
witness_preference,
2458-
hir_id,
2459-
is_under_guard,
2460-
is_top_level,
2461-
)
2462-
})
2463-
.find(|result| result.is_useful())
2464-
.unwrap_or(NotUseful)
2465-
} else {
2466-
// Some constructors are missing, thus we can specialize with the wildcard constructor,
2467-
// which will stand for those constructors that are missing, and behaves like any of
2468-
// them.
2469-
is_useful_specialized(
2470-
pcx,
2471-
v,
2472-
constructor,
2473-
witness_preference,
2474-
hir_id,
2475-
is_under_guard,
2476-
is_top_level,
2477-
)
2478-
}
2479-
};
2437+
let ret = v
2438+
.head_ctor(cx)
2439+
.split(pcx, Some(hir_id))
2440+
.into_iter()
2441+
.map(|ctor| {
2442+
// We cache the result of `Fields::wildcards` because it is used a lot.
2443+
let ctor_wild_subpatterns = Fields::wildcards(pcx, &ctor);
2444+
let matrix = pcx.matrix.specialize_constructor(pcx, &ctor, &ctor_wild_subpatterns);
2445+
// Unwrap is ok: v can always be specialized with its own constructor.
2446+
let v = v.specialize_constructor(pcx, &ctor, &ctor_wild_subpatterns, true).unwrap();
2447+
let usefulness =
2448+
is_useful(pcx.cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false);
2449+
usefulness.apply_constructor(pcx, &ctor, &ctor_wild_subpatterns, is_top_level)
2450+
})
2451+
.find(|result| result.is_useful())
2452+
.unwrap_or(NotUseful);
24802453
debug!("is_useful::returns({:#?}, {:#?}) = {:?}", matrix, v, ret);
24812454
ret
24822455
}
24832456

2484-
/// A shorthand for the `U(S(c, P), S(c, q))` operation from the paper. I.e., `is_useful` applied
2485-
/// to the specialised version of both the pattern matrix `P` and the new pattern `q`.
2486-
fn is_useful_specialized<'p, 'tcx>(
2487-
pcx: PatCtxt<'_, 'p, 'tcx>,
2488-
v: &PatStack<'p, 'tcx>,
2489-
ctor: &Constructor<'tcx>,
2490-
witness_preference: WitnessPreference,
2491-
hir_id: HirId,
2492-
is_under_guard: bool,
2493-
is_top_level: bool,
2494-
) -> Usefulness<'tcx> {
2495-
debug!("is_useful_specialized({:#?}, {:#?}, {:?})", v, ctor, pcx.ty);
2496-
2497-
// We cache the result of `Fields::wildcards` because it is used a lot.
2498-
let ctor_wild_subpatterns = Fields::wildcards(pcx, ctor);
2499-
let matrix = pcx.matrix.specialize_constructor(pcx, ctor, &ctor_wild_subpatterns);
2500-
// Unwrap is ok: v can always be specialized with its own constructor.
2501-
let v = v.specialize_constructor(pcx, ctor, &ctor_wild_subpatterns, true).unwrap();
2502-
let usefulness =
2503-
is_useful(pcx.cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false);
2504-
usefulness.apply_constructor(pcx, ctor, &ctor_wild_subpatterns, is_top_level)
2505-
}
2506-
25072457
/// Determines the constructor that the given pattern can be specialized to.
25082458
/// Returns `None` in case of a catch-all, which can't be specialized.
25092459
fn pat_constructor<'p, 'tcx>(

0 commit comments

Comments
 (0)