diff options
| author | Nadrieril <nadrieril+git@gmail.com> | 2025-07-19 21:18:14 +0200 |
|---|---|---|
| committer | Nadrieril <nadrieril+git@gmail.com> | 2025-07-20 18:27:30 +0200 |
| commit | 9b01de20e10376d379ae32baa6a315d8e30cb351 (patch) | |
| tree | 146d8535eec3612d51f0318528d248dd0847f66f /compiler/rustc_pattern_analysis | |
| parent | 2bb00741d463143a10e632bb118d4ed336dbb75f (diff) | |
| download | rust-9b01de20e10376d379ae32baa6a315d8e30cb351.tar.gz rust-9b01de20e10376d379ae32baa6a315d8e30cb351.zip | |
List all the variants of non-exhaustive enums in exhaustive mode
Diffstat (limited to 'compiler/rustc_pattern_analysis')
| -rw-r--r-- | compiler/rustc_pattern_analysis/src/usefulness.rs | 3 | ||||
| -rw-r--r-- | compiler/rustc_pattern_analysis/tests/common/mod.rs | 27 | ||||
| -rw-r--r-- | compiler/rustc_pattern_analysis/tests/exhaustiveness.rs | 22 |
3 files changed, 46 insertions, 6 deletions
diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs index 91377b2f2bd..19446a1efe9 100644 --- a/compiler/rustc_pattern_analysis/src/usefulness.rs +++ b/compiler/rustc_pattern_analysis/src/usefulness.rs @@ -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. diff --git a/compiler/rustc_pattern_analysis/tests/common/mod.rs b/compiler/rustc_pattern_analysis/tests/common/mod.rs index 7f2c2afcb5b..8497521881a 100644 --- a/compiler/rustc_pattern_analysis/tests/common/mod.rs +++ b/compiler/rustc_pattern_analysis/tests/common/mod.rs @@ -1,3 +1,4 @@ +#![allow(dead_code)] use rustc_pattern_analysis::constructor::{ Constructor, ConstructorSet, IntRange, MaybeInfiniteInt, RangeEnd, VariantVisibility, }; @@ -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 @@ -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. @@ -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:?}"), @@ -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, } } @@ -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() { @@ -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), } diff --git a/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs b/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs index 961693f79c3..14ca0d057f0 100644 --- a/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs +++ b/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs @@ -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!["(_, _)"]); @@ -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, )); |
