Skip to content

Commit 6999acf

Browse files
committed
Suggest never pattern instead of _ for empty types
1 parent f5e7dbe commit 6999acf

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
@@ -1045,10 +1045,32 @@ impl<Cx: TypeCx> ConstructorSet<Cx> {
10451045
// In a `MaybeInvalid` place even an empty pattern may be reachable. We therefore
10461046
// add a dummy empty constructor here, which will be ignored if the place is
10471047
// `ValidOnly`.
1048-
missing_empty.push(NonExhaustive);
1048+
missing_empty.push(Never);
10491049
}
10501050
}
10511051

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

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)