Skip to content

Commit cdafd1e

Browse files
committed
Let MissingConstructors handle the subtleties of missing constructors
1 parent 1190e72 commit cdafd1e

File tree

1 file changed

+72
-89
lines changed
  • compiler/rustc_mir_build/src/thir/pattern

1 file changed

+72
-89
lines changed

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

Lines changed: 72 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1309,11 +1309,6 @@ impl<'tcx> Constructor<'tcx> {
13091309

13101310
Pat { ty, span: DUMMY_SP, kind: Box::new(pat) }
13111311
}
1312-
1313-
/// Like `apply`, but where all the subpatterns are wildcards `_`.
1314-
fn apply_wildcards<'a>(&self, cx: &MatchCheckCtxt<'a, 'tcx>, ty: Ty<'tcx>) -> Pat<'tcx> {
1315-
self.apply(cx, ty, Fields::wildcards(cx, self, ty))
1316-
}
13171312
}
13181313

13191314
/// Some fields need to be explicitly hidden away in certain cases; see the comment above the
@@ -1649,35 +1644,15 @@ impl<'tcx> Usefulness<'tcx> {
16491644
}
16501645
}
16511646

1652-
fn apply_wildcard(self, ty: Ty<'tcx>) -> Self {
1653-
match self {
1654-
UsefulWithWitness(witnesses) => {
1655-
let wild = Pat::wildcard_from_ty(ty);
1656-
UsefulWithWitness(
1657-
witnesses
1658-
.into_iter()
1659-
.map(|mut witness| {
1660-
witness.0.push(wild.clone());
1661-
witness
1662-
})
1663-
.collect(),
1664-
)
1665-
}
1666-
x => x,
1667-
}
1668-
}
1669-
1670-
fn apply_missing_ctors(
1647+
fn apply_wildcard<'p>(
16711648
self,
1672-
cx: &MatchCheckCtxt<'_, 'tcx>,
1673-
ty: Ty<'tcx>,
1674-
missing_ctors: &MissingConstructors<'tcx>,
1649+
cx: &MatchCheckCtxt<'p, 'tcx>,
1650+
pcx: PatCtxt<'tcx>,
1651+
missing_ctors: MissingConstructors<'tcx>,
16751652
) -> Self {
16761653
match self {
16771654
UsefulWithWitness(witnesses) => {
1678-
let new_patterns: Vec<_> =
1679-
missing_ctors.iter().map(|ctor| ctor.apply_wildcards(cx, ty)).collect();
1680-
// Add the new patterns to each witness
1655+
let new_patterns = missing_ctors.report_patterns(cx, pcx);
16811656
UsefulWithWitness(
16821657
witnesses
16831658
.into_iter()
@@ -2270,11 +2245,21 @@ impl<'tcx> std::cmp::PartialEq for IntRange<'tcx> {
22702245
struct MissingConstructors<'tcx> {
22712246
all_ctors: Vec<Constructor<'tcx>>,
22722247
used_ctors: Vec<Constructor<'tcx>>,
2248+
is_top_level: bool,
22732249
}
22742250

22752251
impl<'tcx> MissingConstructors<'tcx> {
2276-
fn new(all_ctors: Vec<Constructor<'tcx>>, used_ctors: Vec<Constructor<'tcx>>) -> Self {
2277-
MissingConstructors { all_ctors, used_ctors }
2252+
fn new<'p>(
2253+
cx: &MatchCheckCtxt<'p, 'tcx>,
2254+
pcx: PatCtxt<'tcx>,
2255+
matrix: &Matrix<'p, 'tcx>,
2256+
is_top_level: bool,
2257+
) -> Self {
2258+
let used_ctors: Vec<Constructor<'_>> =
2259+
matrix.head_ctors(cx).cloned().filter(|c| !c.is_wildcard()).collect();
2260+
let all_ctors = all_constructors(cx, pcx);
2261+
2262+
MissingConstructors { all_ctors, used_ctors, is_top_level }
22782263
}
22792264

22802265
fn into_inner(self) -> (Vec<Constructor<'tcx>>, Vec<Constructor<'tcx>>) {
@@ -2284,16 +2269,64 @@ impl<'tcx> MissingConstructors<'tcx> {
22842269
fn is_empty(&self) -> bool {
22852270
self.iter().next().is_none()
22862271
}
2287-
/// Whether this contains all the constructors for the given type or only a
2288-
/// subset.
2289-
fn all_ctors_are_missing(&self) -> bool {
2290-
self.used_ctors.is_empty()
2291-
}
22922272

22932273
/// Iterate over all_ctors \ used_ctors
22942274
fn iter<'a>(&'a self) -> impl Iterator<Item = Constructor<'tcx>> + Captures<'a> {
22952275
self.all_ctors.iter().flat_map(move |req_ctor| req_ctor.subtract_ctors(&self.used_ctors))
22962276
}
2277+
2278+
/// List the patterns corresponding to the missing constructors. In some cases, instead of
2279+
/// listing all constructors of a given type, we prefer to simply report a wildcard.
2280+
fn report_patterns<'p>(
2281+
&self,
2282+
cx: &MatchCheckCtxt<'p, 'tcx>,
2283+
pcx: PatCtxt<'tcx>,
2284+
) -> SmallVec<[Pat<'tcx>; 1]> {
2285+
// There are 2 ways we can report a witness here.
2286+
// Commonly, we can report all the "free"
2287+
// constructors as witnesses, e.g., if we have:
2288+
//
2289+
// ```
2290+
// enum Direction { N, S, E, W }
2291+
// let Direction::N = ...;
2292+
// ```
2293+
//
2294+
// we can report 3 witnesses: `S`, `E`, and `W`.
2295+
//
2296+
// However, there is a case where we don't want
2297+
// to do this and instead report a single `_` witness:
2298+
// if the user didn't actually specify a constructor
2299+
// in this arm, e.g., in
2300+
//
2301+
// ```
2302+
// let x: (Direction, Direction, bool) = ...;
2303+
// let (_, _, false) = x;
2304+
// ```
2305+
//
2306+
// we don't want to show all 16 possible witnesses
2307+
// `(<direction-1>, <direction-2>, true)` - we are
2308+
// satisfied with `(_, _, true)`. In this case,
2309+
// `used_ctors` is empty.
2310+
// The exception is: if we are at the top-level, for example in an empty match, we
2311+
// sometimes prefer reporting the list of constructors instead of just `_`.
2312+
let report_when_all_missing = self.is_top_level && !IntRange::is_integral(pcx.ty);
2313+
if self.used_ctors.is_empty() && !report_when_all_missing {
2314+
// All constructors are unused. Report only a wildcard
2315+
// rather than each individual constructor.
2316+
smallvec![Pat::wildcard_from_ty(pcx.ty)]
2317+
} else {
2318+
// Construct for each missing constructor a "wild" version of this
2319+
// constructor, that matches everything that can be built with
2320+
// it. For example, if `ctor` is a `Constructor::Variant` for
2321+
// `Option::Some`, we get the pattern `Some(_)`.
2322+
self.iter()
2323+
.map(|missing_ctor| {
2324+
let fields = Fields::wildcards(cx, &missing_ctor, pcx.ty);
2325+
missing_ctor.apply(cx, pcx.ty, fields)
2326+
})
2327+
.collect()
2328+
}
2329+
}
22972330
}
22982331

22992332
impl<'tcx> fmt::Debug for MissingConstructors<'tcx> {
@@ -2434,14 +2467,6 @@ crate fn is_useful<'p, 'tcx>(
24342467
} else {
24352468
debug!("is_useful - expanding wildcard");
24362469

2437-
let used_ctors: Vec<Constructor<'_>> =
2438-
matrix.head_ctors(cx).cloned().filter(|c| !c.is_wildcard()).collect();
2439-
debug!("is_useful_used_ctors = {:#?}", used_ctors);
2440-
// `all_ctors` are all the constructors for the given type, which
2441-
// should all be represented (or caught with the wild pattern `_`).
2442-
let all_ctors = all_constructors(cx, pcx);
2443-
debug!("is_useful_all_ctors = {:#?}", all_ctors);
2444-
24452470
// `missing_ctors` is the set of constructors from the same type as the
24462471
// first column of `matrix` that are matched only by wildcard patterns
24472472
// from the first column.
@@ -2453,7 +2478,7 @@ crate fn is_useful<'p, 'tcx>(
24532478
// Missing constructors are those that are not matched by any non-wildcard patterns in the
24542479
// current column. We only fully construct them on-demand, because they're rarely used and
24552480
// can be big.
2456-
let missing_ctors = MissingConstructors::new(all_ctors, used_ctors);
2481+
let missing_ctors = MissingConstructors::new(cx, pcx, matrix, is_top_level);
24572482

24582483
debug!("is_useful_missing_ctors.empty()={:#?}", missing_ctors.is_empty(),);
24592484

@@ -2485,49 +2510,7 @@ crate fn is_useful<'p, 'tcx>(
24852510
let usefulness =
24862511
is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false);
24872512

2488-
// In this case, there's at least one "free"
2489-
// constructor that is only matched against by
2490-
// wildcard patterns.
2491-
//
2492-
// There are 2 ways we can report a witness here.
2493-
// Commonly, we can report all the "free"
2494-
// constructors as witnesses, e.g., if we have:
2495-
//
2496-
// ```
2497-
// enum Direction { N, S, E, W }
2498-
// let Direction::N = ...;
2499-
// ```
2500-
//
2501-
// we can report 3 witnesses: `S`, `E`, and `W`.
2502-
//
2503-
// However, there is a case where we don't want
2504-
// to do this and instead report a single `_` witness:
2505-
// if the user didn't actually specify a constructor
2506-
// in this arm, e.g., in
2507-
//
2508-
// ```
2509-
// let x: (Direction, Direction, bool) = ...;
2510-
// let (_, _, false) = x;
2511-
// ```
2512-
//
2513-
// we don't want to show all 16 possible witnesses
2514-
// `(<direction-1>, <direction-2>, true)` - we are
2515-
// satisfied with `(_, _, true)`. In this case,
2516-
// `used_ctors` is empty.
2517-
// The exception is: if we are at the top-level, for example in an empty match, we
2518-
// sometimes prefer reporting the list of constructors instead of just `_`.
2519-
let report_ctors_rather_than_wildcard = is_top_level && !IntRange::is_integral(pcx.ty);
2520-
if missing_ctors.all_ctors_are_missing() && !report_ctors_rather_than_wildcard {
2521-
// All constructors are unused. Add a wild pattern
2522-
// rather than each individual constructor.
2523-
usefulness.apply_wildcard(pcx.ty)
2524-
} else {
2525-
// Construct for each missing constructor a "wild" version of this
2526-
// constructor, that matches everything that can be built with
2527-
// it. For example, if `ctor` is a `Constructor::Variant` for
2528-
// `Option::Some`, we get the pattern `Some(_)`.
2529-
usefulness.apply_missing_ctors(cx, pcx.ty, &missing_ctors)
2530-
}
2513+
usefulness.apply_wildcard(cx, pcx, missing_ctors)
25312514
}
25322515
};
25332516
debug!("is_useful::returns({:#?}, {:#?}) = {:?}", matrix, v, ret);

0 commit comments

Comments
 (0)