about summary refs log tree commit diff
path: root/compiler/rustc_pattern_analysis/src
diff options
context:
space:
mode:
authorNadrieril <nadrieril+git@gmail.com>2024-02-28 22:37:11 +0100
committerNadrieril <nadrieril+git@gmail.com>2024-03-12 21:38:30 +0100
commit9f2aa5b85a2584568f1ad34f23d029eeafb20d4b (patch)
treec8a43d2517eb0ffb2d70c25293588473fcd17e4f /compiler/rustc_pattern_analysis/src
parent1ec73d70fac58055eb1a2249279fad81b986edc2 (diff)
downloadrust-9f2aa5b85a2584568f1ad34f23d029eeafb20d4b.tar.gz
rust-9f2aa5b85a2584568f1ad34f23d029eeafb20d4b.zip
Suggest never pattern instead of `_` for empty types
Diffstat (limited to 'compiler/rustc_pattern_analysis/src')
-rw-r--r--compiler/rustc_pattern_analysis/src/constructor.rs24
-rw-r--r--compiler/rustc_pattern_analysis/src/pat.rs12
2 files changed, 32 insertions, 4 deletions
diff --git a/compiler/rustc_pattern_analysis/src/constructor.rs b/compiler/rustc_pattern_analysis/src/constructor.rs
index 66c9e2e1840..b4d32782acf 100644
--- a/compiler/rustc_pattern_analysis/src/constructor.rs
+++ b/compiler/rustc_pattern_analysis/src/constructor.rs
@@ -1048,10 +1048,32 @@ impl<Cx: TypeCx> ConstructorSet<Cx> {
                 // In a `MaybeInvalid` place even an empty pattern may be reachable. We therefore
                 // add a dummy empty constructor here, which will be ignored if the place is
                 // `ValidOnly`.
-                missing_empty.push(NonExhaustive);
+                missing_empty.push(Never);
             }
         }
 
         SplitConstructorSet { present, missing, missing_empty }
     }
+
+    /// Whether this set only contains empty constructors.
+    pub(crate) fn all_empty(&self) -> bool {
+        match self {
+            ConstructorSet::Bool
+            | ConstructorSet::Integers { .. }
+            | ConstructorSet::Ref
+            | ConstructorSet::Union
+            | ConstructorSet::Unlistable => false,
+            ConstructorSet::NoConstructors => true,
+            ConstructorSet::Struct { empty } => *empty,
+            ConstructorSet::Variants { variants, non_exhaustive } => {
+                !*non_exhaustive
+                    && variants
+                        .iter()
+                        .all(|visibility| matches!(visibility, VariantVisibility::Empty))
+            }
+            ConstructorSet::Slice { array_len, subtype_is_empty } => {
+                *subtype_is_empty && matches!(array_len, Some(1..))
+            }
+        }
+    }
 }
diff --git a/compiler/rustc_pattern_analysis/src/pat.rs b/compiler/rustc_pattern_analysis/src/pat.rs
index 3395054b7b3..780a386fe65 100644
--- a/compiler/rustc_pattern_analysis/src/pat.rs
+++ b/compiler/rustc_pattern_analysis/src/pat.rs
@@ -292,18 +292,24 @@ impl<Cx: TypeCx> WitnessPat<Cx> {
     pub(crate) fn new(ctor: Constructor<Cx>, fields: Vec<Self>, ty: Cx::Ty) -> Self {
         Self { ctor, fields, ty }
     }
-    pub(crate) fn wildcard(ty: Cx::Ty) -> Self {
-        Self::new(Wildcard, Vec::new(), ty)
+    /// Create a wildcard pattern for this type. If the type is empty, we create a `!` pattern.
+    pub(crate) fn wildcard(cx: &Cx, ty: Cx::Ty) -> Self {
+        let is_empty = cx.ctors_for_ty(&ty).is_ok_and(|ctors| ctors.all_empty());
+        let ctor = if is_empty { Never } else { Wildcard };
+        Self::new(ctor, Vec::new(), ty)
     }
 
     /// Construct a pattern that matches everything that starts with this constructor.
     /// For example, if `ctor` is a `Constructor::Variant` for `Option::Some`, we get the pattern
     /// `Some(_)`.
     pub(crate) fn wild_from_ctor(cx: &Cx, ctor: Constructor<Cx>, ty: Cx::Ty) -> Self {
+        if matches!(ctor, Wildcard) {
+            return Self::wildcard(cx, ty);
+        }
         let fields = cx
             .ctor_sub_tys(&ctor, &ty)
             .filter(|(_, PrivateUninhabitedField(skip))| !skip)
-            .map(|(ty, _)| Self::wildcard(ty))
+            .map(|(ty, _)| Self::wildcard(cx, ty))
             .collect();
         Self::new(ctor, fields, ty)
     }