let deref patterns participate in usefulness/exhaustiveness

This does not yet handle the case of mixed deref patterns with normal
constructors; it'll ICE in `Constructor::is_covered_by`. That'll be
fixed in a later commit.
This commit is contained in:
dianne
2025-04-17 02:33:24 -07:00
parent 669c1ab967
commit b41d8bde00
8 changed files with 47 additions and 24 deletions

View File

@@ -696,6 +696,10 @@ pub enum Constructor<Cx: PatCx> {
F128Range(IeeeFloat<QuadS>, IeeeFloat<QuadS>, RangeEnd),
/// String literals. Strings are not quite the same as `&[u8]` so we treat them separately.
Str(Cx::StrLit),
/// Deref patterns (enabled by the `deref_patterns` feature) provide a way of matching on a
/// smart pointer ADT through its pointee. They don't directly correspond to ADT constructors,
/// and currently are not supported alongside them. Carries the type of the pointee.
DerefPattern(Cx::Ty),
/// Constants that must not be matched structurally. They are treated as black boxes for the
/// purposes of exhaustiveness: we must not inspect them, and they don't count towards making a
/// match exhaustive.
@@ -740,6 +744,7 @@ impl<Cx: PatCx> Clone for Constructor<Cx> {
Constructor::F64Range(lo, hi, end) => Constructor::F64Range(*lo, *hi, *end),
Constructor::F128Range(lo, hi, end) => Constructor::F128Range(*lo, *hi, *end),
Constructor::Str(value) => Constructor::Str(value.clone()),
Constructor::DerefPattern(ty) => Constructor::DerefPattern(ty.clone()),
Constructor::Opaque(inner) => Constructor::Opaque(inner.clone()),
Constructor::Or => Constructor::Or,
Constructor::Never => Constructor::Never,
@@ -856,6 +861,10 @@ impl<Cx: PatCx> Constructor<Cx> {
}
(Slice(self_slice), Slice(other_slice)) => self_slice.is_covered_by(*other_slice),
// Deref patterns only interact with other deref patterns. Prior to usefulness analysis,
// we ensure they don't appear alongside any other non-wild non-opaque constructors.
(DerefPattern(_), DerefPattern(_)) => true,
// Opaque constructors don't interact with anything unless they come from the
// syntactically identical pattern.
(Opaque(self_id), Opaque(other_id)) => self_id == other_id,
@@ -932,6 +941,7 @@ impl<Cx: PatCx> Constructor<Cx> {
F64Range(lo, hi, end) => write!(f, "{lo}{end}{hi}")?,
F128Range(lo, hi, end) => write!(f, "{lo}{end}{hi}")?,
Str(value) => write!(f, "{value:?}")?,
DerefPattern(_) => write!(f, "deref!({:?})", fields.next().unwrap())?,
Opaque(..) => write!(f, "<constant pattern>")?,
Or => {
for pat in fields {
@@ -1039,8 +1049,17 @@ impl<Cx: PatCx> ConstructorSet<Cx> {
let mut missing = Vec::new();
// Constructors in `ctors`, except wildcards and opaques.
let mut seen = Vec::new();
// If we see a deref pattern, it must be the only non-wildcard non-opaque constructor; we
// ensure this prior to analysis.
let mut deref_pat_present = false;
for ctor in ctors.cloned() {
match ctor {
DerefPattern(..) => {
if !deref_pat_present {
deref_pat_present = true;
present.push(ctor);
}
}
Opaque(..) => present.push(ctor),
Wildcard => {} // discard wildcards
_ => seen.push(ctor),
@@ -1048,6 +1067,9 @@ impl<Cx: PatCx> ConstructorSet<Cx> {
}
match self {
_ if deref_pat_present => {
// Deref patterns are the only constructor; nothing is missing.
}
ConstructorSet::Struct { empty } => {
if !seen.is_empty() {
present.push(Struct);