Skip to content

Commit 9f2aa5b

Browse files
committed
Suggest never pattern instead of _ for empty types
1 parent 1ec73d7 commit 9f2aa5b

File tree

6 files changed

+97
-69
lines changed

6 files changed

+97
-69
lines changed

compiler/rustc_pattern_analysis/src/constructor.rs

+23-1
Original file line numberDiff line numberDiff line change
@@ -1048,10 +1048,32 @@ impl<Cx: TypeCx> ConstructorSet<Cx> {
10481048
// In a `MaybeInvalid` place even an empty pattern may be reachable. We therefore
10491049
// add a dummy empty constructor here, which will be ignored if the place is
10501050
// `ValidOnly`.
1051-
missing_empty.push(NonExhaustive);
1051+
missing_empty.push(Never);
10521052
}
10531053
}
10541054

10551055
SplitConstructorSet { present, missing, missing_empty }
10561056
}
1057+
1058+
/// Whether this set only contains empty constructors.
1059+
pub(crate) fn all_empty(&self) -> bool {
1060+
match self {
1061+
ConstructorSet::Bool
1062+
| ConstructorSet::Integers { .. }
1063+
| ConstructorSet::Ref
1064+
| ConstructorSet::Union
1065+
| ConstructorSet::Unlistable => false,
1066+
ConstructorSet::NoConstructors => true,
1067+
ConstructorSet::Struct { empty } => *empty,
1068+
ConstructorSet::Variants { variants, non_exhaustive } => {
1069+
!*non_exhaustive
1070+
&& variants
1071+
.iter()
1072+
.all(|visibility| matches!(visibility, VariantVisibility::Empty))
1073+
}
1074+
ConstructorSet::Slice { array_len, subtype_is_empty } => {
1075+
*subtype_is_empty && matches!(array_len, Some(1..))
1076+
}
1077+
}
1078+
}
10571079
}

compiler/rustc_pattern_analysis/src/pat.rs

+9-3
Original file line numberDiff line numberDiff line change
@@ -292,18 +292,24 @@ impl<Cx: TypeCx> WitnessPat<Cx> {
292292
pub(crate) fn new(ctor: Constructor<Cx>, fields: Vec<Self>, ty: Cx::Ty) -> Self {
293293
Self { ctor, fields, ty }
294294
}
295-
pub(crate) fn wildcard(ty: Cx::Ty) -> Self {
296-
Self::new(Wildcard, Vec::new(), ty)
295+
/// Create a wildcard pattern for this type. If the type is empty, we create a `!` pattern.
296+
pub(crate) fn wildcard(cx: &Cx, ty: Cx::Ty) -> Self {
297+
let is_empty = cx.ctors_for_ty(&ty).is_ok_and(|ctors| ctors.all_empty());
298+
let ctor = if is_empty { Never } else { Wildcard };
299+
Self::new(ctor, Vec::new(), ty)
297300
}
298301

299302
/// Construct a pattern that matches everything that starts with this constructor.
300303
/// For example, if `ctor` is a `Constructor::Variant` for `Option::Some`, we get the pattern
301304
/// `Some(_)`.
302305
pub(crate) fn wild_from_ctor(cx: &Cx, ctor: Constructor<Cx>, ty: Cx::Ty) -> Self {
306+
if matches!(ctor, Wildcard) {
307+
return Self::wildcard(cx, ty);
308+
}
303309
let fields = cx
304310
.ctor_sub_tys(&ctor, &ty)
305311
.filter(|(_, PrivateUninhabitedField(skip))| !skip)
306-
.map(|(ty, _)| Self::wildcard(ty))
312+
.map(|(ty, _)| Self::wildcard(cx, ty))
307313
.collect();
308314
Self::new(ctor, fields, ty)
309315
}

0 commit comments

Comments
 (0)