Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
List all the variants of non-exhaustive enums in exhaustive mode
  • Loading branch information
Nadrieril committed Jul 20, 2025
commit 9b01de20e10376d379ae32baa6a315d8e30cb351
3 changes: 2 additions & 1 deletion compiler/rustc_pattern_analysis/src/usefulness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -994,7 +994,8 @@ impl<Cx: PatCx> PlaceInfo<Cx> {
if !missing_ctors.is_empty() && !report_individual_missing_ctors {
// Report `_` as missing.
missing_ctors = vec![Constructor::Wildcard];
} else if missing_ctors.iter().any(|c| c.is_non_exhaustive()) {
} else if missing_ctors.iter().any(|c| c.is_non_exhaustive()) && !cx.exhaustive_witnesses()
{
// We need to report a `_` anyway, so listing other constructors would be redundant.
// `NonExhaustive` is displayed as `_` just like `Wildcard`, but it will be picked
// up by diagnostics to add a note about why `_` is required here.
Expand Down
27 changes: 24 additions & 3 deletions compiler/rustc_pattern_analysis/tests/common/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![allow(dead_code)]
use rustc_pattern_analysis::constructor::{
Constructor, ConstructorSet, IntRange, MaybeInfiniteInt, RangeEnd, VariantVisibility,
};
Expand All @@ -22,8 +23,10 @@ fn init_tracing() {
.try_init();
}

pub const UNIT: Ty = Ty::Tuple(&[]);
pub const NEVER: Ty = Ty::Enum(&[]);

/// A simple set of types.
#[allow(dead_code)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub(super) enum Ty {
/// Booleans
Expand All @@ -38,6 +41,8 @@ pub(super) enum Ty {
BigStruct { arity: usize, ty: &'static Ty },
/// A enum with `arity` variants of type `ty`.
BigEnum { arity: usize, ty: &'static Ty },
/// Like `Enum` but non-exhaustive.
NonExhaustiveEnum(&'static [Ty]),
}

/// The important logic.
Expand All @@ -47,7 +52,7 @@ impl Ty {
match (ctor, *self) {
(Struct, Ty::Tuple(tys)) => tys.iter().copied().collect(),
(Struct, Ty::BigStruct { arity, ty }) => (0..arity).map(|_| *ty).collect(),
(Variant(i), Ty::Enum(tys)) => vec![tys[*i]],
(Variant(i), Ty::Enum(tys) | Ty::NonExhaustiveEnum(tys)) => vec![tys[*i]],
(Variant(_), Ty::BigEnum { ty, .. }) => vec![*ty],
(Bool(..) | IntRange(..) | NonExhaustive | Missing | Wildcard, _) => vec![],
_ => panic!("Unexpected ctor {ctor:?} for type {self:?}"),
Expand All @@ -61,6 +66,7 @@ impl Ty {
Ty::Enum(tys) => tys.iter().all(|ty| ty.is_empty()),
Ty::BigStruct { arity, ty } => arity != 0 && ty.is_empty(),
Ty::BigEnum { arity, ty } => arity == 0 || ty.is_empty(),
Ty::NonExhaustiveEnum(..) => false,
}
}

Expand Down Expand Up @@ -90,6 +96,19 @@ impl Ty {
.collect(),
non_exhaustive: false,
},
Ty::NonExhaustiveEnum(tys) => ConstructorSet::Variants {
variants: tys
.iter()
.map(|ty| {
if ty.is_empty() {
VariantVisibility::Empty
} else {
VariantVisibility::Visible
}
})
.collect(),
non_exhaustive: true,
},
Ty::BigEnum { arity: 0, .. } => ConstructorSet::NoConstructors,
Ty::BigEnum { arity, ty } => {
let vis = if ty.is_empty() {
Expand All @@ -113,7 +132,9 @@ impl Ty {
match (*self, ctor) {
(Ty::Tuple(..), _) => Ok(()),
(Ty::BigStruct { .. }, _) => write!(f, "BigStruct"),
(Ty::Enum(..), Constructor::Variant(i)) => write!(f, "Enum::Variant{i}"),
(Ty::Enum(..) | Ty::NonExhaustiveEnum(..), Constructor::Variant(i)) => {
write!(f, "Enum::Variant{i}")
}
(Ty::BigEnum { .. }, Constructor::Variant(i)) => write!(f, "BigEnum::Variant{i}"),
_ => write!(f, "{:?}::{:?}", self, ctor),
}
Expand Down
22 changes: 20 additions & 2 deletions compiler/rustc_pattern_analysis/tests/exhaustiveness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ fn test_nested() {
#[test]
fn test_witnesses() {
// TY = Option<bool>
const TY: Ty = Ty::Enum(&[Ty::Bool, Ty::Tuple(&[])]);
const TY: Ty = Ty::Enum(&[Ty::Bool, UNIT]);
// ty = (Option<bool>, Option<bool>)
let ty = Ty::Tuple(&[TY, TY]);
assert_witnesses(AllOfThem, ty, vec![], vec!["(_, _)"]);
Expand Down Expand Up @@ -158,12 +158,30 @@ fn test_witnesses() {
),
vec!["(_, Enum::Variant0(true))", "(_, Enum::Variant1(_))"],
);

let ty = Ty::NonExhaustiveEnum(&[UNIT, UNIT, UNIT]);
assert_witnesses(
OnlySome,
ty,
pats!(ty;
Variant.0,
),
vec!["_"],
);
assert_witnesses(
AllOfThem,
ty,
pats!(ty;
Variant.0,
),
vec!["Enum::Variant1(_)", "Enum::Variant2(_)", "_"],
);
}

#[test]
fn test_empty() {
// `TY = Result<bool, !>`
const TY: Ty = Ty::Enum(&[Ty::Bool, Ty::Enum(&[])]);
const TY: Ty = Ty::Enum(&[Ty::Bool, NEVER]);
assert_exhaustive(pats!(TY;
Variant.0,
));
Expand Down