Skip to content

Commit 92101b7

Browse files
committed
Define a MissingConstructors struct for cleanliness
1 parent cc4583d commit 92101b7

File tree

1 file changed

+75
-41
lines changed

1 file changed

+75
-41
lines changed

src/librustc_mir/hair/pattern/_match.rs

Lines changed: 75 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1279,43 +1279,76 @@ impl<'tcx> IntRange<'tcx> {
12791279
}
12801280
}
12811281

1282-
type MissingConstructors<'a, 'tcx, F> =
1283-
std::iter::FlatMap<std::slice::Iter<'a, Constructor<'tcx>>, Vec<Constructor<'tcx>>, F>;
1284-
// Compute a set of constructors equivalent to `all_ctors \ used_ctors`. This
1285-
// returns an iterator, so that we only construct the whole set if needed.
1286-
fn compute_missing_ctors<'a, 'tcx>(
1282+
// A struct to compute a set of constructors equivalent to `all_ctors \ used_ctors`.
1283+
struct MissingConstructors<'tcx> {
12871284
tcx: TyCtxt<'tcx>,
12881285
param_env: ty::ParamEnv<'tcx>,
1289-
all_ctors: &'a Vec<Constructor<'tcx>>,
1290-
used_ctors: &'a Vec<Constructor<'tcx>>,
1291-
) -> MissingConstructors<'a, 'tcx, impl FnMut(&'a Constructor<'tcx>) -> Vec<Constructor<'tcx>>> {
1292-
all_ctors.iter().flat_map(move |req_ctor| {
1293-
let mut refined_ctors = vec![req_ctor.clone()];
1294-
for used_ctor in used_ctors {
1295-
if used_ctor == req_ctor {
1296-
// If a constructor appears in a `match` arm, we can
1297-
// eliminate it straight away.
1298-
refined_ctors = vec![]
1299-
} else if let Some(interval) = IntRange::from_ctor(tcx, param_env, used_ctor) {
1300-
// Refine the required constructors for the type by subtracting
1301-
// the range defined by the current constructor pattern.
1302-
refined_ctors = interval.subtract_from(tcx, param_env, refined_ctors);
1303-
}
1286+
all_ctors: Vec<Constructor<'tcx>>,
1287+
used_ctors: Vec<Constructor<'tcx>>,
1288+
}
1289+
1290+
impl<'tcx> MissingConstructors<'tcx> {
1291+
fn new(
1292+
tcx: TyCtxt<'tcx>,
1293+
param_env: ty::ParamEnv<'tcx>,
1294+
all_ctors: Vec<Constructor<'tcx>>,
1295+
used_ctors: Vec<Constructor<'tcx>>,
1296+
) -> Self {
1297+
MissingConstructors { tcx, param_env, all_ctors, used_ctors }
1298+
}
13041299

1305-
// If the constructor patterns that have been considered so far
1306-
// already cover the entire range of values, then we know the
1307-
// constructor is not missing, and we can move on to the next one.
1308-
if refined_ctors.is_empty() {
1309-
break;
1300+
fn into_inner(self) -> (Vec<Constructor<'tcx>>, Vec<Constructor<'tcx>>) {
1301+
(self.all_ctors, self.used_ctors)
1302+
}
1303+
1304+
fn is_empty(&self) -> bool {
1305+
self.iter().next().is_none()
1306+
}
1307+
/// Whether this contains all the constructors for the given type or only a
1308+
/// subset.
1309+
fn all_ctors_are_missing(&self) -> bool {
1310+
self.used_ctors.is_empty()
1311+
}
1312+
1313+
/// Iterate over all_ctors \ used_ctors
1314+
fn iter<'a>(&'a self) -> impl Iterator<Item = Constructor<'tcx>> + Captures<'a> {
1315+
self.all_ctors.iter().flat_map(move |req_ctor| {
1316+
let mut refined_ctors = vec![req_ctor.clone()];
1317+
for used_ctor in &self.used_ctors {
1318+
if used_ctor == req_ctor {
1319+
// If a constructor appears in a `match` arm, we can
1320+
// eliminate it straight away.
1321+
refined_ctors = vec![]
1322+
} else if let Some(interval) =
1323+
IntRange::from_ctor(self.tcx, self.param_env, used_ctor)
1324+
{
1325+
// Refine the required constructors for the type by subtracting
1326+
// the range defined by the current constructor pattern.
1327+
refined_ctors = interval.subtract_from(self.tcx, self.param_env, refined_ctors);
1328+
}
1329+
1330+
// If the constructor patterns that have been considered so far
1331+
// already cover the entire range of values, then we know the
1332+
// constructor is not missing, and we can move on to the next one.
1333+
if refined_ctors.is_empty() {
1334+
break;
1335+
}
13101336
}
1311-
}
13121337

1313-
// If a constructor has not been matched, then it is missing.
1314-
// We add `refined_ctors` instead of `req_ctor`, because then we can
1315-
// provide more detailed error information about precisely which
1316-
// ranges have been omitted.
1317-
refined_ctors
1318-
})
1338+
// If a constructor has not been matched, then it is missing.
1339+
// We add `refined_ctors` instead of `req_ctor`, because then we can
1340+
// provide more detailed error information about precisely which
1341+
// ranges have been omitted.
1342+
refined_ctors
1343+
})
1344+
}
1345+
}
1346+
1347+
impl<'tcx> fmt::Debug for MissingConstructors<'tcx> {
1348+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1349+
let ctors: Vec<_> = self.iter().collect();
1350+
write!(f, "{:?}", ctors)
1351+
}
13191352
}
13201353

13211354
/// Algorithm from http://moscova.inria.fr/~maranget/papers/warn/index.html.
@@ -1426,6 +1459,9 @@ pub fn is_useful<'p, 'a, 'tcx>(
14261459
let all_ctors = all_constructors(cx, pcx);
14271460
debug!("all_ctors = {:#?}", all_ctors);
14281461

1462+
let is_privately_empty = all_ctors.is_empty() && !cx.is_uninhabited(pcx.ty);
1463+
let is_declared_nonexhaustive = cx.is_non_exhaustive_enum(pcx.ty) && !cx.is_local(pcx.ty);
1464+
14291465
// `missing_ctors` is the set of constructors from the same type as the
14301466
// first column of `matrix` that are matched only by wildcard patterns
14311467
// from the first column.
@@ -1449,14 +1485,11 @@ pub fn is_useful<'p, 'a, 'tcx>(
14491485
// non-wildcard patterns in the current column. To determine if
14501486
// the set is empty, we can check that `.peek().is_none()`, so
14511487
// we only fully construct them on-demand, because they're rarely used and can be big.
1452-
let mut missing_ctors =
1453-
compute_missing_ctors(cx.tcx, cx.param_env, &all_ctors, &used_ctors).peekable();
1488+
let missing_ctors = MissingConstructors::new(cx.tcx, cx.param_env, all_ctors, used_ctors);
14541489

1455-
let is_privately_empty = all_ctors.is_empty() && !cx.is_uninhabited(pcx.ty);
1456-
let is_declared_nonexhaustive = cx.is_non_exhaustive_enum(pcx.ty) && !cx.is_local(pcx.ty);
14571490
debug!(
14581491
"missing_ctors.empty()={:#?} is_privately_empty={:#?} is_declared_nonexhaustive={:#?}",
1459-
missing_ctors.peek().is_none(),
1492+
missing_ctors.is_empty(),
14601493
is_privately_empty,
14611494
is_declared_nonexhaustive
14621495
);
@@ -1467,8 +1500,8 @@ pub fn is_useful<'p, 'a, 'tcx>(
14671500
|| is_declared_nonexhaustive
14681501
|| (pcx.ty.is_ptr_sized_integral() && !cx.tcx.features().precise_pointer_size_matching);
14691502

1470-
if missing_ctors.peek().is_none() && !is_non_exhaustive {
1471-
drop(missing_ctors); // It was borrowing `all_ctors`, which we want to move.
1503+
if missing_ctors.is_empty() && !is_non_exhaustive {
1504+
let (all_ctors, _) = missing_ctors.into_inner();
14721505
split_grouped_constructors(
14731506
cx.tcx,
14741507
cx.param_env,
@@ -1532,7 +1565,8 @@ pub fn is_useful<'p, 'a, 'tcx>(
15321565
// `(<direction-1>, <direction-2>, true)` - we are
15331566
// satisfied with `(_, _, true)`. In this case,
15341567
// `used_ctors` is empty.
1535-
let new_patterns = if is_non_exhaustive || used_ctors.is_empty() {
1568+
let new_patterns = if is_non_exhaustive || missing_ctors.all_ctors_are_missing()
1569+
{
15361570
// All constructors are unused. Add a wild pattern
15371571
// rather than each individual constructor.
15381572
vec![Pat { ty: pcx.ty, span: DUMMY_SP, kind: box PatKind::Wild }]
@@ -1541,7 +1575,7 @@ pub fn is_useful<'p, 'a, 'tcx>(
15411575
// constructor, that matches everything that can be built with
15421576
// it. For example, if `ctor` is a `Constructor::Variant` for
15431577
// `Option::Some`, we get the pattern `Some(_)`.
1544-
missing_ctors.map(|ctor| ctor.apply_wildcards(cx, pcx.ty)).collect()
1578+
missing_ctors.iter().map(|ctor| ctor.apply_wildcards(cx, pcx.ty)).collect()
15451579
};
15461580
// Add the new patterns to each witness
15471581
let new_witnesses = witnesses

0 commit comments

Comments
 (0)