Skip to content

Commit 387215f

Browse files
committed
Clarify the Wildcard/Missing situation
1 parent f6fa49f commit 387215f

File tree

2 files changed

+39
-43
lines changed

2 files changed

+39
-43
lines changed

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

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,7 @@
7272
//! The only place where we care about which constructors `Missing` represents is in diagnostics
7373
//! (see `super::usefulness::WitnessMatrix::apply_constructor`).
7474
//!
75-
//! Extra special implementation detail: in fact, in the case where all the constructors are
76-
//! missing, we replace `Missing` with `Wildcard` to signal this. It only makes a difference for
77-
//! diagnostics: for `Missing` we list the missing constructors; for `Wildcard` we only output `_`.
78-
//!
79-
//! FIXME(Nadrieril): maybe `Missing { report_all: bool }` would be less confusing.
80-
//!
81-
//! We choose whether to specialize with `Missing`/`Wildcard` in
75+
//! We choose whether to specialize with `Missing` in
8276
//! `super::usefulness::compute_exhaustiveness_and_reachability`.
8377
//!
8478
//!
@@ -720,8 +714,11 @@ pub(super) enum Constructor<'tcx> {
720714
/// `#[doc(hidden)]` ones.
721715
Hidden,
722716
/// Fake extra constructor for constructors that are not seen in the matrix, as explained at the
723-
/// top of the file.
724-
Missing,
717+
/// top of the file. `report_individual_ctors` is for diagnostics; see
718+
/// `WitnessMatrix::apply_constructor`.
719+
Missing {
720+
report_individual_ctors: bool,
721+
},
725722
}
726723

727724
impl<'tcx> Constructor<'tcx> {
@@ -809,10 +806,11 @@ impl<'tcx> Constructor<'tcx> {
809806
#[inline]
810807
pub(super) fn is_covered_by<'p>(&self, pcx: &PatCtxt<'_, 'p, 'tcx>, other: &Self) -> bool {
811808
match (self, other) {
809+
(Wildcard, _) => bug!("Constructor splitting should not have returned `Wildcard`"),
812810
// Wildcards cover anything
813811
(_, Wildcard) => true,
814812
// Only a wildcard pattern can match these special constructors.
815-
(Wildcard | Missing { .. } | NonExhaustive | Hidden, _) => false,
813+
(Missing { .. } | NonExhaustive | Hidden, _) => false,
816814

817815
(Single, Single) => true,
818816
(Variant(self_id), Variant(other_id)) => self_id == other_id,

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

Lines changed: 31 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -925,7 +925,7 @@ impl<'tcx> WitnessMatrix<'tcx> {
925925
}
926926

927927
/// Reverses specialization by the `Missing` constructor by pushing a whole new pattern.
928-
fn push_pattern(&mut self, pat: &WitnessPat<'tcx>) {
928+
fn push_pattern(&mut self, pat: WitnessPat<'tcx>) {
929929
for witness in self.0.iter_mut() {
930930
witness.push_pattern(pat.clone())
931931
}
@@ -941,31 +941,34 @@ impl<'tcx> WitnessMatrix<'tcx> {
941941
if self.is_empty() {
942942
return;
943943
}
944-
if matches!(ctor, Constructor::Wildcard) {
945-
let pat = WitnessPat::wild_from_ctor(pcx, Constructor::Wildcard);
946-
self.push_pattern(&pat);
947-
} else if matches!(ctor, Constructor::Missing) {
948-
// We got the special `Missing` constructor, so each of the missing constructors gives a
949-
// new pattern that is not caught by the match. We list those patterns and push them
950-
// onto our current witnesses.
951-
if missing_ctors.iter().any(|c| c.is_non_exhaustive()) {
952-
// We only report `_` here; listing other constructors would be redundant.
953-
let pat = WitnessPat::wild_from_ctor(pcx, Constructor::NonExhaustive);
954-
self.push_pattern(&pat);
955-
} else {
956-
let old_witnesses = std::mem::replace(self, Self::empty());
957-
for ctor in missing_ctors {
958-
let pat = WitnessPat::wild_from_ctor(pcx, ctor.clone());
959-
let mut witnesses_with_missing_ctor = old_witnesses.clone();
960-
witnesses_with_missing_ctor.push_pattern(&pat);
961-
self.extend(witnesses_with_missing_ctor)
944+
if let Constructor::Missing { report_individual_ctors } = ctor {
945+
// We got the special `Missing` constructor that stands for the constructors not present
946+
// in the match.
947+
if *report_individual_ctors {
948+
if missing_ctors.iter().any(|c| c.is_non_exhaustive()) {
949+
// We only report `_` here; listing other constructors would be redundant.
950+
let pat = WitnessPat::wild_from_ctor(pcx, Constructor::NonExhaustive);
951+
self.push_pattern(pat);
952+
} else {
953+
let old_witnesses = std::mem::replace(self, Self::empty());
954+
for ctor in missing_ctors {
955+
// For each missing constructor `c`, we push a `c(_, _, _)` witness
956+
// appropriately filled with wildcards.
957+
let pat = WitnessPat::wild_from_ctor(pcx, ctor.clone());
958+
let mut witnesses_with_missing_ctor = old_witnesses.clone();
959+
witnesses_with_missing_ctor.push_pattern(pat);
960+
self.extend(witnesses_with_missing_ctor)
961+
}
962962
}
963+
} else {
964+
// Report only a wildcard.
965+
let pat = WitnessPat::wild_from_ctor(pcx, Constructor::Wildcard);
966+
self.push_pattern(pat);
963967
}
964968
} else if !missing_ctors.is_empty() {
965-
// `ctor` isn't `Wildcard` or `Missing` and some ctors are missing, so we know
966-
// `split_ctors` will contain `Wildcard` or `Missing`.
967-
// For diagnostic purposes we choose to discard witnesses we got under `ctor`, which
968-
// will let only the `Wildcard` or `Missing` be reported.
969+
// `ctor` isn't `Missing` and some ctors are missing, so we know `split_ctors` will
970+
// contain `Missing`. For diagnostic purposes we choose to discard witnesses we got
971+
// under `ctor`, which will let only the `Missing` be reported.
969972
self.0.clear();
970973
} else {
971974
for witness in self.0.iter_mut() {
@@ -1025,18 +1028,13 @@ fn compute_exhaustiveness_and_reachability<'p, 'tcx>(
10251028
let ctors = matrix.heads().map(|p| p.ctor());
10261029
let split_set = ConstructorSet::for_ty(pcx.cx, pcx.ty).split(pcx, ctors);
10271030
let mut split_ctors = split_set.present;
1028-
// We want to iterate over a full set of constructors, so if any is missing we add a wildcard.
1031+
// We want to iterate over a full set of constructors, so if some are missing we add a `Missing`
1032+
// to represent them.
10291033
if !split_set.missing.is_empty() {
10301034
let all_missing = split_ctors.is_empty();
1031-
let always_report_missing = is_top_level && !IntRange::is_integral(pcx.ty);
1032-
let ctor = if all_missing && !always_report_missing {
1033-
Constructor::Wildcard
1034-
} else {
1035-
// Like `Wildcard`, except if it doesn't match a row this will report all the missing
1036-
// constructors instead of just `_`.
1037-
Constructor::Missing
1038-
};
1039-
split_ctors.push(ctor);
1035+
let always_report_all = is_top_level && !IntRange::is_integral(pcx.ty);
1036+
let report_individual_ctors = always_report_all || !all_missing;
1037+
split_ctors.push(Constructor::Missing { report_individual_ctors });
10401038
}
10411039

10421040
let mut ret = WitnessMatrix::empty();

0 commit comments

Comments
 (0)