Skip to content

Commit 0c02c19

Browse files
committed
Remove duplicate logic in compute_missing_constructors
This is equivalent to the previous code in terms of performance. The expensive path is clearly identical. The fast path is also the same, because in both cases we loop until we get a non-empty `refined_ctors`, and then stop there. So the new code doesn't compute anything more than the previous did.
1 parent 5e734be commit 0c02c19

File tree

1 file changed

+35
-84
lines changed

1 file changed

+35
-84
lines changed

src/librustc_mir/hair/pattern/_match.rs

Lines changed: 35 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1255,41 +1255,17 @@ impl<'tcx> IntRange<'tcx> {
12551255
}
12561256
}
12571257

1258-
// A request for missing constructor data in terms of either:
1259-
// - whether or not there any missing constructors; or
1260-
// - the actual set of missing constructors.
1261-
#[derive(PartialEq)]
1262-
enum MissingCtorsInfo {
1263-
Emptiness,
1264-
Ctors,
1265-
}
1266-
1267-
// Used by `compute_missing_ctors`.
1268-
#[derive(Debug, PartialEq)]
1269-
enum MissingCtors<'tcx> {
1270-
Empty,
1271-
NonEmpty,
1272-
1273-
// Note that the Vec can be empty.
1274-
Ctors(Vec<Constructor<'tcx>>),
1275-
}
1276-
1277-
// When `info` is `MissingCtorsInfo::Ctors`, compute a set of constructors
1278-
// equivalent to `all_ctors \ used_ctors`. When `info` is
1279-
// `MissingCtorsInfo::Emptiness`, just determines if that set is empty or not.
1280-
// (The split logic gives a performance win, because we always need to know if
1281-
// the set is empty, but we rarely need the full set, and it can be expensive
1282-
// to compute the full set.)
1283-
fn compute_missing_ctors<'tcx>(
1284-
info: MissingCtorsInfo,
1258+
type MissingConstructors<'a, 'tcx, F> =
1259+
std::iter::FlatMap<std::slice::Iter<'a, Constructor<'tcx>>, Vec<Constructor<'tcx>>, F>;
1260+
// Compute a set of constructors equivalent to `all_ctors \ used_ctors`. This
1261+
// returns an iterator, so that we only construct the whole set if needed.
1262+
fn compute_missing_ctors<'a, 'tcx>(
12851263
tcx: TyCtxt<'tcx>,
12861264
param_env: ty::ParamEnv<'tcx>,
1287-
all_ctors: &Vec<Constructor<'tcx>>,
1288-
used_ctors: &Vec<Constructor<'tcx>>,
1289-
) -> MissingCtors<'tcx> {
1290-
let mut missing_ctors = vec![];
1291-
1292-
for req_ctor in all_ctors {
1265+
all_ctors: &'a Vec<Constructor<'tcx>>,
1266+
used_ctors: &'a Vec<Constructor<'tcx>>,
1267+
) -> MissingConstructors<'a, 'tcx, impl FnMut(&'a Constructor<'tcx>) -> Vec<Constructor<'tcx>>> {
1268+
all_ctors.iter().flat_map(move |req_ctor| {
12931269
let mut refined_ctors = vec![req_ctor.clone()];
12941270
for used_ctor in used_ctors {
12951271
if used_ctor == req_ctor {
@@ -1303,32 +1279,19 @@ fn compute_missing_ctors<'tcx>(
13031279
}
13041280

13051281
// If the constructor patterns that have been considered so far
1306-
// already cover the entire range of values, then we the
1282+
// already cover the entire range of values, then we know the
13071283
// constructor is not missing, and we can move on to the next one.
13081284
if refined_ctors.is_empty() {
13091285
break;
13101286
}
13111287
}
1288+
13121289
// If a constructor has not been matched, then it is missing.
13131290
// We add `refined_ctors` instead of `req_ctor`, because then we can
13141291
// provide more detailed error information about precisely which
13151292
// ranges have been omitted.
1316-
if info == MissingCtorsInfo::Emptiness {
1317-
if !refined_ctors.is_empty() {
1318-
// The set is non-empty; return early.
1319-
return MissingCtors::NonEmpty;
1320-
}
1321-
} else {
1322-
missing_ctors.extend(refined_ctors);
1323-
}
1324-
}
1325-
1326-
if info == MissingCtorsInfo::Emptiness {
1327-
// If we reached here, the set is empty.
1328-
MissingCtors::Empty
1329-
} else {
1330-
MissingCtors::Ctors(missing_ctors)
1331-
}
1293+
refined_ctors
1294+
})
13321295
}
13331296

13341297
/// Algorithm from http://moscova.inria.fr/~maranget/papers/warn/index.html.
@@ -1459,22 +1422,19 @@ pub fn is_useful<'p, 'a, 'tcx>(
14591422
// needed for that case.
14601423

14611424
// Missing constructors are those that are not matched by any
1462-
// non-wildcard patterns in the current column. We always determine if
1463-
// the set is empty, but we only fully construct them on-demand,
1464-
// because they're rarely used and can be big.
1465-
let cheap_missing_ctors = compute_missing_ctors(
1466-
MissingCtorsInfo::Emptiness,
1467-
cx.tcx,
1468-
cx.param_env,
1469-
&all_ctors,
1470-
&used_ctors,
1471-
);
1425+
// non-wildcard patterns in the current column. To determine if
1426+
// the set is empty, we can check that `.peek().is_none()`, so
1427+
// we only fully construct them on-demand, because they're rarely used and can be big.
1428+
let mut missing_ctors =
1429+
compute_missing_ctors(cx.tcx, cx.param_env, &all_ctors, &used_ctors).peekable();
14721430

14731431
let is_privately_empty = all_ctors.is_empty() && !cx.is_uninhabited(pcx.ty);
14741432
let is_declared_nonexhaustive = cx.is_non_exhaustive_enum(pcx.ty) && !cx.is_local(pcx.ty);
14751433
debug!(
1476-
"cheap_missing_ctors={:#?} is_privately_empty={:#?} is_declared_nonexhaustive={:#?}",
1477-
cheap_missing_ctors, is_privately_empty, is_declared_nonexhaustive
1434+
"missing_ctors.empty()={:#?} is_privately_empty={:#?} is_declared_nonexhaustive={:#?}",
1435+
missing_ctors.peek().is_none(),
1436+
is_privately_empty,
1437+
is_declared_nonexhaustive
14781438
);
14791439

14801440
// For privately empty and non-exhaustive enums, we work as if there were an "extra"
@@ -1483,7 +1443,8 @@ pub fn is_useful<'p, 'a, 'tcx>(
14831443
|| is_declared_nonexhaustive
14841444
|| (pcx.ty.is_ptr_sized_integral() && !cx.tcx.features().precise_pointer_size_matching);
14851445

1486-
if cheap_missing_ctors == MissingCtors::Empty && !is_non_exhaustive {
1446+
if missing_ctors.peek().is_none() && !is_non_exhaustive {
1447+
drop(missing_ctors); // It was borrowing `all_ctors`, which we want to move.
14871448
split_grouped_constructors(
14881449
cx.tcx,
14891450
cx.param_env,
@@ -1561,28 +1522,18 @@ pub fn is_useful<'p, 'a, 'tcx>(
15611522
})
15621523
.collect()
15631524
} else {
1564-
let expensive_missing_ctors = compute_missing_ctors(
1565-
MissingCtorsInfo::Ctors,
1566-
cx.tcx,
1567-
cx.param_env,
1568-
&all_ctors,
1569-
&used_ctors,
1570-
);
1571-
if let MissingCtors::Ctors(missing_ctors) = expensive_missing_ctors {
1572-
pats.into_iter()
1573-
.flat_map(|witness| {
1574-
missing_ctors.iter().map(move |ctor| {
1575-
// Extends the witness with a "wild" version of this
1576-
// constructor, that matches everything that can be built with
1577-
// it. For example, if `ctor` is a `Constructor::Variant` for
1578-
// `Option::Some`, this pushes the witness for `Some(_)`.
1579-
witness.clone().push_wild_constructor(cx, ctor, pcx.ty)
1580-
})
1525+
let missing_ctors: Vec<_> = missing_ctors.collect();
1526+
pats.into_iter()
1527+
.flat_map(|witness| {
1528+
missing_ctors.iter().map(move |ctor| {
1529+
// Extends the witness with a "wild" version of this
1530+
// constructor, that matches everything that can be built with
1531+
// it. For example, if `ctor` is a `Constructor::Variant` for
1532+
// `Option::Some`, this pushes the witness for `Some(_)`.
1533+
witness.clone().push_wild_constructor(cx, ctor, pcx.ty)
15811534
})
1582-
.collect()
1583-
} else {
1584-
bug!("cheap missing ctors")
1585-
}
1535+
})
1536+
.collect()
15861537
};
15871538
UsefulWithWitness(new_witnesses)
15881539
}

0 commit comments

Comments
 (0)