Skip to content

Commit 9b01de2

Browse files
committed
List all the variants of non-exhaustive enums in exhaustive mode
1 parent 2bb0074 commit 9b01de2

File tree

3 files changed

+46
-6
lines changed

3 files changed

+46
-6
lines changed

compiler/rustc_pattern_analysis/src/usefulness.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -994,7 +994,8 @@ impl<Cx: PatCx> PlaceInfo<Cx> {
994994
if !missing_ctors.is_empty() && !report_individual_missing_ctors {
995995
// Report `_` as missing.
996996
missing_ctors = vec![Constructor::Wildcard];
997-
} else if missing_ctors.iter().any(|c| c.is_non_exhaustive()) {
997+
} else if missing_ctors.iter().any(|c| c.is_non_exhaustive()) && !cx.exhaustive_witnesses()
998+
{
998999
// We need to report a `_` anyway, so listing other constructors would be redundant.
9991000
// `NonExhaustive` is displayed as `_` just like `Wildcard`, but it will be picked
10001001
// up by diagnostics to add a note about why `_` is required here.

compiler/rustc_pattern_analysis/tests/common/mod.rs

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#![allow(dead_code)]
12
use rustc_pattern_analysis::constructor::{
23
Constructor, ConstructorSet, IntRange, MaybeInfiniteInt, RangeEnd, VariantVisibility,
34
};
@@ -22,8 +23,10 @@ fn init_tracing() {
2223
.try_init();
2324
}
2425

26+
pub const UNIT: Ty = Ty::Tuple(&[]);
27+
pub const NEVER: Ty = Ty::Enum(&[]);
28+
2529
/// A simple set of types.
26-
#[allow(dead_code)]
2730
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
2831
pub(super) enum Ty {
2932
/// Booleans
@@ -38,6 +41,8 @@ pub(super) enum Ty {
3841
BigStruct { arity: usize, ty: &'static Ty },
3942
/// A enum with `arity` variants of type `ty`.
4043
BigEnum { arity: usize, ty: &'static Ty },
44+
/// Like `Enum` but non-exhaustive.
45+
NonExhaustiveEnum(&'static [Ty]),
4146
}
4247

4348
/// The important logic.
@@ -47,7 +52,7 @@ impl Ty {
4752
match (ctor, *self) {
4853
(Struct, Ty::Tuple(tys)) => tys.iter().copied().collect(),
4954
(Struct, Ty::BigStruct { arity, ty }) => (0..arity).map(|_| *ty).collect(),
50-
(Variant(i), Ty::Enum(tys)) => vec![tys[*i]],
55+
(Variant(i), Ty::Enum(tys) | Ty::NonExhaustiveEnum(tys)) => vec![tys[*i]],
5156
(Variant(_), Ty::BigEnum { ty, .. }) => vec![*ty],
5257
(Bool(..) | IntRange(..) | NonExhaustive | Missing | Wildcard, _) => vec![],
5358
_ => panic!("Unexpected ctor {ctor:?} for type {self:?}"),
@@ -61,6 +66,7 @@ impl Ty {
6166
Ty::Enum(tys) => tys.iter().all(|ty| ty.is_empty()),
6267
Ty::BigStruct { arity, ty } => arity != 0 && ty.is_empty(),
6368
Ty::BigEnum { arity, ty } => arity == 0 || ty.is_empty(),
69+
Ty::NonExhaustiveEnum(..) => false,
6470
}
6571
}
6672

@@ -90,6 +96,19 @@ impl Ty {
9096
.collect(),
9197
non_exhaustive: false,
9298
},
99+
Ty::NonExhaustiveEnum(tys) => ConstructorSet::Variants {
100+
variants: tys
101+
.iter()
102+
.map(|ty| {
103+
if ty.is_empty() {
104+
VariantVisibility::Empty
105+
} else {
106+
VariantVisibility::Visible
107+
}
108+
})
109+
.collect(),
110+
non_exhaustive: true,
111+
},
93112
Ty::BigEnum { arity: 0, .. } => ConstructorSet::NoConstructors,
94113
Ty::BigEnum { arity, ty } => {
95114
let vis = if ty.is_empty() {
@@ -113,7 +132,9 @@ impl Ty {
113132
match (*self, ctor) {
114133
(Ty::Tuple(..), _) => Ok(()),
115134
(Ty::BigStruct { .. }, _) => write!(f, "BigStruct"),
116-
(Ty::Enum(..), Constructor::Variant(i)) => write!(f, "Enum::Variant{i}"),
135+
(Ty::Enum(..) | Ty::NonExhaustiveEnum(..), Constructor::Variant(i)) => {
136+
write!(f, "Enum::Variant{i}")
137+
}
117138
(Ty::BigEnum { .. }, Constructor::Variant(i)) => write!(f, "BigEnum::Variant{i}"),
118139
_ => write!(f, "{:?}::{:?}", self, ctor),
119140
}

compiler/rustc_pattern_analysis/tests/exhaustiveness.rs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ fn test_nested() {
117117
#[test]
118118
fn test_witnesses() {
119119
// TY = Option<bool>
120-
const TY: Ty = Ty::Enum(&[Ty::Bool, Ty::Tuple(&[])]);
120+
const TY: Ty = Ty::Enum(&[Ty::Bool, UNIT]);
121121
// ty = (Option<bool>, Option<bool>)
122122
let ty = Ty::Tuple(&[TY, TY]);
123123
assert_witnesses(AllOfThem, ty, vec![], vec!["(_, _)"]);
@@ -158,12 +158,30 @@ fn test_witnesses() {
158158
),
159159
vec!["(_, Enum::Variant0(true))", "(_, Enum::Variant1(_))"],
160160
);
161+
162+
let ty = Ty::NonExhaustiveEnum(&[UNIT, UNIT, UNIT]);
163+
assert_witnesses(
164+
OnlySome,
165+
ty,
166+
pats!(ty;
167+
Variant.0,
168+
),
169+
vec!["_"],
170+
);
171+
assert_witnesses(
172+
AllOfThem,
173+
ty,
174+
pats!(ty;
175+
Variant.0,
176+
),
177+
vec!["Enum::Variant1(_)", "Enum::Variant2(_)", "_"],
178+
);
161179
}
162180

163181
#[test]
164182
fn test_empty() {
165183
// `TY = Result<bool, !>`
166-
const TY: Ty = Ty::Enum(&[Ty::Bool, Ty::Enum(&[])]);
184+
const TY: Ty = Ty::Enum(&[Ty::Bool, NEVER]);
167185
assert_exhaustive(pats!(TY;
168186
Variant.0,
169187
));

0 commit comments

Comments
 (0)