Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit bbb4ac0

Browse files
committed
Rebrand MissingConstructors as SplitWildcard
1 parent 9d0c2ed commit bbb4ac0

File tree

2 files changed

+67
-49
lines changed

2 files changed

+67
-49
lines changed

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

Lines changed: 63 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -695,20 +695,9 @@ impl<'tcx> Constructor<'tcx> {
695695
/// Two constructors that are not in the matrix will either both be caught (by a wildcard), or
696696
/// both not be caught. Therefore we can keep the missing constructors grouped together.
697697
fn split_wildcard<'p>(pcx: PatCtxt<'_, 'p, 'tcx>) -> SmallVec<[Self; 1]> {
698-
// Missing constructors are those that are not matched by any non-wildcard patterns in the
699-
// current column. We only fully construct them on-demand, because they're rarely used and
700-
// can be big.
701-
let missing_ctors = MissingConstructors::new(pcx);
702-
if missing_ctors.is_empty(pcx) {
703-
// All the constructors are present in the matrix, so we just go through them all.
704-
// We must also split them first.
705-
missing_ctors.all_ctors
706-
} else {
707-
// Some constructors are missing, thus we can specialize with the wildcard constructor,
708-
// which will stand for those constructors that are missing, and behaves like any of
709-
// them.
710-
smallvec![Wildcard]
711-
}
698+
let mut split_wildcard = SplitWildcard::new(pcx);
699+
split_wildcard.split(pcx);
700+
split_wildcard.into_ctors(pcx)
712701
}
713702

714703
/// Returns whether `self` is covered by `other`, i.e. whether `self` is a subset of `other`.
@@ -811,7 +800,7 @@ impl<'tcx> Constructor<'tcx> {
811800
/// `Option<!>`, we do not include `Some(_)` in the returned list of constructors.
812801
/// Invariant: this returns an empty `Vec` if and only if the type is uninhabited (as determined by
813802
/// `cx.is_uninhabited()`).
814-
fn all_constructors<'p, 'tcx>(pcx: PatCtxt<'_, 'p, 'tcx>) -> Vec<Constructor<'tcx>> {
803+
fn all_constructors<'p, 'tcx>(pcx: PatCtxt<'_, 'p, 'tcx>) -> SmallVec<[Constructor<'tcx>; 1]> {
815804
debug!("all_constructors({:?})", pcx.ty);
816805
let cx = pcx.cx;
817806
let make_range = |start, end| {
@@ -821,19 +810,19 @@ fn all_constructors<'p, 'tcx>(pcx: PatCtxt<'_, 'p, 'tcx>) -> Vec<Constructor<'tc
821810
)
822811
};
823812
match pcx.ty.kind() {
824-
ty::Bool => vec![make_range(0, 1)],
813+
ty::Bool => smallvec![make_range(0, 1)],
825814
ty::Array(sub_ty, len) if len.try_eval_usize(cx.tcx, cx.param_env).is_some() => {
826815
let len = len.eval_usize(cx.tcx, cx.param_env);
827816
if len != 0 && cx.is_uninhabited(sub_ty) {
828-
vec![]
817+
smallvec![]
829818
} else {
830-
vec![Slice(Slice::new(Some(len), VarLen(0, 0)))]
819+
smallvec![Slice(Slice::new(Some(len), VarLen(0, 0)))]
831820
}
832821
}
833822
// Treat arrays of a constant but unknown length like slices.
834823
ty::Array(sub_ty, _) | ty::Slice(sub_ty) => {
835824
let kind = if cx.is_uninhabited(sub_ty) { FixedLen(0) } else { VarLen(0, 0) };
836-
vec![Slice(Slice::new(None, kind))]
825+
smallvec![Slice(Slice::new(None, kind))]
837826
}
838827
ty::Adt(def, substs) if def.is_enum() => {
839828
// If the enum is declared as `#[non_exhaustive]`, we treat it as if it had an
@@ -863,7 +852,7 @@ fn all_constructors<'p, 'tcx>(pcx: PatCtxt<'_, 'p, 'tcx>) -> Vec<Constructor<'tc
863852
&& !pcx.is_top_level;
864853

865854
if is_secretly_empty || is_declared_nonexhaustive {
866-
vec![NonExhaustive]
855+
smallvec![NonExhaustive]
867856
} else if cx.tcx.features().exhaustive_patterns {
868857
// If `exhaustive_patterns` is enabled, we exclude variants known to be
869858
// uninhabited.
@@ -880,7 +869,7 @@ fn all_constructors<'p, 'tcx>(pcx: PatCtxt<'_, 'p, 'tcx>) -> Vec<Constructor<'tc
880869
}
881870
}
882871
ty::Char => {
883-
vec![
872+
smallvec![
884873
// The valid Unicode Scalar Value ranges.
885874
make_range('\u{0000}' as u128, '\u{D7FF}' as u128),
886875
make_range('\u{E000}' as u128, '\u{10FFFF}' as u128),
@@ -893,66 +882,94 @@ fn all_constructors<'p, 'tcx>(pcx: PatCtxt<'_, 'p, 'tcx>) -> Vec<Constructor<'tc
893882
// `usize`/`isize` are not allowed to be matched exhaustively unless the
894883
// `precise_pointer_size_matching` feature is enabled. So we treat those types like
895884
// `#[non_exhaustive]` enums by returning a special unmatcheable constructor.
896-
vec![NonExhaustive]
885+
smallvec![NonExhaustive]
897886
}
898887
&ty::Int(ity) => {
899888
let bits = Integer::from_attr(&cx.tcx, SignedInt(ity)).size().bits() as u128;
900889
let min = 1u128 << (bits - 1);
901890
let max = min - 1;
902-
vec![make_range(min, max)]
891+
smallvec![make_range(min, max)]
903892
}
904893
&ty::Uint(uty) => {
905894
let size = Integer::from_attr(&cx.tcx, UnsignedInt(uty)).size();
906895
let max = size.truncate(u128::MAX);
907-
vec![make_range(0, max)]
896+
smallvec![make_range(0, max)]
908897
}
909898
// If `exhaustive_patterns` is disabled and our scrutinee is the never type, we cannot
910899
// expose its emptiness. The exception is if the pattern is at the top level, because we
911900
// want empty matches to be considered exhaustive.
912901
ty::Never if !cx.tcx.features().exhaustive_patterns && !pcx.is_top_level => {
913-
vec![NonExhaustive]
902+
smallvec![NonExhaustive]
914903
}
915-
ty::Never => vec![],
916-
_ if cx.is_uninhabited(pcx.ty) => vec![],
917-
ty::Adt(..) | ty::Tuple(..) | ty::Ref(..) => vec![Single],
904+
ty::Never => smallvec![],
905+
_ if cx.is_uninhabited(pcx.ty) => smallvec![],
906+
ty::Adt(..) | ty::Tuple(..) | ty::Ref(..) => smallvec![Single],
918907
// This type is one for which we cannot list constructors, like `str` or `f64`.
919-
_ => vec![NonExhaustive],
908+
_ => smallvec![NonExhaustive],
920909
}
921910
}
922911

923-
// A struct to compute a set of constructors equivalent to `all_ctors \ used_ctors`.
912+
/// A wildcard constructor that we split relative to the constructors in the matrix, as explained
913+
/// at the top of the file.
914+
/// For splitting wildcards, there are two groups of constructors: there are the constructors
915+
/// actually present in the matrix (`matrix_ctors`), and the constructors not present. Two
916+
/// constructors that are not in the matrix will either both be covered (by a wildcard), or both
917+
/// not be covered by any given row. Therefore we can keep the missing constructors grouped
918+
/// together.
924919
#[derive(Debug)]
925-
pub(super) struct MissingConstructors<'tcx> {
920+
pub(super) struct SplitWildcard<'tcx> {
921+
/// Constructors seen in the matrix.
922+
matrix_ctors: Vec<Constructor<'tcx>>,
923+
/// All the constructors for this type
926924
all_ctors: SmallVec<[Constructor<'tcx>; 1]>,
927-
used_ctors: Vec<Constructor<'tcx>>,
928925
}
929926

930-
impl<'tcx> MissingConstructors<'tcx> {
927+
impl<'tcx> SplitWildcard<'tcx> {
931928
pub(super) fn new<'p>(pcx: PatCtxt<'_, 'p, 'tcx>) -> Self {
932-
let used_ctors: Vec<Constructor<'_>> =
929+
let matrix_ctors = Vec::new();
930+
let all_ctors = all_constructors(pcx);
931+
SplitWildcard { matrix_ctors, all_ctors }
932+
}
933+
934+
/// Pass a set of constructors relative to which to split this one. Don't call twice, it won't
935+
/// do what you want.
936+
pub(super) fn split(&mut self, pcx: PatCtxt<'_, '_, 'tcx>) {
937+
self.matrix_ctors =
933938
pcx.matrix.head_ctors(pcx.cx).cloned().filter(|c| !c.is_wildcard()).collect();
934939
// Since `all_ctors` never contains wildcards, this won't recurse further.
935-
let all_ctors =
936-
all_constructors(pcx).into_iter().flat_map(|ctor| ctor.split(pcx)).collect();
937-
938-
MissingConstructors { all_ctors, used_ctors }
940+
self.all_ctors = self.all_ctors.iter().flat_map(|ctor| ctor.split(pcx)).collect();
939941
}
940942

941-
fn is_empty<'p>(&self, pcx: PatCtxt<'_, 'p, 'tcx>) -> bool {
942-
self.iter(pcx).next().is_none()
943+
/// Whether there are any value constructors for this type that are not present in the matrix.
944+
fn any_missing(&self, pcx: PatCtxt<'_, '_, 'tcx>) -> bool {
945+
self.iter_missing(pcx).next().is_some()
943946
}
944947

945-
/// Iterate over all_ctors \ used_ctors
946-
fn iter<'a, 'p>(
948+
/// Iterate over the constructors for this type that are not present in the matrix.
949+
fn iter_missing<'a, 'p>(
947950
&'a self,
948951
pcx: PatCtxt<'a, 'p, 'tcx>,
949952
) -> impl Iterator<Item = &'a Constructor<'tcx>> + Captures<'p> {
950-
self.all_ctors.iter().filter(move |ctor| !ctor.is_covered_by_any(pcx, &self.used_ctors))
953+
self.all_ctors.iter().filter(move |ctor| !ctor.is_covered_by_any(pcx, &self.matrix_ctors))
954+
}
955+
956+
/// Return the set of constructors resulting from splitting the wildcard. As explained at the
957+
/// top of the file, if any constructors are missing we can ignore the present ones.
958+
fn into_ctors(self, pcx: PatCtxt<'_, '_, 'tcx>) -> SmallVec<[Constructor<'tcx>; 1]> {
959+
if self.any_missing(pcx) {
960+
// Some constructors are missing, thus we can specialize with the wildcard constructor,
961+
// which will stand for those constructors that are missing, and matches the same rows
962+
// as any of them (namely the wildcard rows).
963+
return smallvec![Wildcard];
964+
}
965+
966+
// All the constructors are present in the matrix, so we just go through them all.
967+
self.all_ctors
951968
}
952969

953970
/// List the patterns corresponding to the missing constructors. In some cases, instead of
954971
/// listing all constructors of a given type, we prefer to simply report a wildcard.
955-
pub(super) fn report_patterns<'p>(
972+
pub(super) fn report_missing_patterns<'p>(
956973
&self,
957974
pcx: PatCtxt<'_, 'p, 'tcx>,
958975
) -> SmallVec<[Pat<'tcx>; 1]> {
@@ -984,7 +1001,7 @@ impl<'tcx> MissingConstructors<'tcx> {
9841001
// The exception is: if we are at the top-level, for example in an empty match, we
9851002
// sometimes prefer reporting the list of constructors instead of just `_`.
9861003
let report_when_all_missing = pcx.is_top_level && !IntRange::is_integral(pcx.ty);
987-
if self.used_ctors.is_empty() && !report_when_all_missing {
1004+
if self.matrix_ctors.is_empty() && !report_when_all_missing {
9881005
// All constructors are unused. Report only a wildcard
9891006
// rather than each individual constructor.
9901007
smallvec![Pat::wildcard_from_ty(pcx.ty)]
@@ -993,7 +1010,7 @@ impl<'tcx> MissingConstructors<'tcx> {
9931010
// constructor, that matches everything that can be built with
9941011
// it. For example, if `ctor` is a `Constructor::Variant` for
9951012
// `Option::Some`, we get the pattern `Some(_)`.
996-
self.iter(pcx)
1013+
self.iter_missing(pcx)
9971014
.map(|missing_ctor| Fields::wildcards(pcx, &missing_ctor).apply(pcx, missing_ctor))
9981015
.collect()
9991016
}

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@
306306
use self::Usefulness::*;
307307
use self::WitnessPreference::*;
308308

309-
use super::deconstruct_pat::{Constructor, Fields, MissingConstructors};
309+
use super::deconstruct_pat::{Constructor, Fields, SplitWildcard};
310310
use super::{Pat, PatKind};
311311
use super::{PatternFoldable, PatternFolder};
312312

@@ -810,8 +810,9 @@ impl<'tcx> Usefulness<'tcx> {
810810
match self {
811811
UsefulWithWitness(witnesses) => {
812812
let new_witnesses = if ctor.is_wildcard() {
813-
let missing_ctors = MissingConstructors::new(pcx);
814-
let new_patterns = missing_ctors.report_patterns(pcx);
813+
let mut split_wildcard = SplitWildcard::new(pcx);
814+
split_wildcard.split(pcx);
815+
let new_patterns = split_wildcard.report_missing_patterns(pcx);
815816
witnesses
816817
.into_iter()
817818
.flat_map(|witness| {

0 commit comments

Comments
 (0)