Unnamed repository; edit this file 'description' to name the repository.
Merge pull request #18645 from Veykril/push-yruoyrvrsntw
fix: Non-exhaustive structs may be empty
Lukas Wirth 2024-12-09
parent d824871 · parent 55a7ee8 · commit 067b4a3
-rw-r--r--crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs6
-rw-r--r--crates/hir-ty/src/inhabitedness.rs8
-rw-r--r--crates/ide-diagnostics/src/handlers/missing_match_arms.rs19
3 files changed, 21 insertions, 12 deletions
diff --git a/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs b/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
index 58de19ba81..5452f5c680 100644
--- a/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
+++ b/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
@@ -383,9 +383,6 @@ impl<'db> PatCx for MatchCheckCtx<'db> {
} else {
let variant = Self::variant_id_for_adt(self.db, ctor, adt).unwrap();
- // Whether we must not match the fields of this variant exhaustively.
- let is_non_exhaustive =
- LazyCell::new(|| self.is_foreign_non_exhaustive(adt));
let visibilities = LazyCell::new(|| self.db.field_visibilities(variant));
self.list_variant_fields(ty, variant)
@@ -396,8 +393,7 @@ impl<'db> PatCx for MatchCheckCtx<'db> {
.is_visible_from(self.db.upcast(), self.module)
};
let is_uninhabited = self.is_uninhabited(&ty);
- let private_uninhabited =
- is_uninhabited && (!is_visible() || *is_non_exhaustive);
+ let private_uninhabited = is_uninhabited && !is_visible();
(ty, PrivateUninhabitedField(private_uninhabited))
})
.collect()
diff --git a/crates/hir-ty/src/inhabitedness.rs b/crates/hir-ty/src/inhabitedness.rs
index c0a781b17e..56b549436c 100644
--- a/crates/hir-ty/src/inhabitedness.rs
+++ b/crates/hir-ty/src/inhabitedness.rs
@@ -5,8 +5,7 @@ use chalk_ir::{
visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor},
DebruijnIndex,
};
-use hir_def::{visibility::Visibility, AdtId, EnumVariantId, HasModule, ModuleId, VariantId};
-use intern::sym;
+use hir_def::{visibility::Visibility, AdtId, EnumVariantId, ModuleId, VariantId};
use rustc_hash::FxHashSet;
use crate::{
@@ -118,11 +117,6 @@ impl UninhabitedFrom<'_> {
variant: VariantId,
subst: &Substitution,
) -> ControlFlow<VisiblyUninhabited> {
- let is_local = variant.krate(self.db.upcast()) == self.target_mod.krate();
- if !is_local && self.db.attrs(variant.into()).by_key(&sym::non_exhaustive).exists() {
- return CONTINUE_OPAQUELY_INHABITED;
- }
-
let variant_data = self.db.variant_data(variant);
let fields = variant_data.fields();
if fields.is_empty() {
diff --git a/crates/ide-diagnostics/src/handlers/missing_match_arms.rs b/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
index f39738f2fb..08e6e7dced 100644
--- a/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
+++ b/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
@@ -1114,6 +1114,25 @@ fn test(x: Option<lib::PrivatelyUninhabited>) {
}
}
+ #[test]
+ fn non_exhaustive_may_be_empty() {
+ check_diagnostics_no_bails(
+ r"
+//- /main.rs crate:main deps:dep
+// In a different crate
+fn empty_match_on_empty_struct<T>(x: dep::UninhabitedStruct) -> T {
+ match x {}
+}
+//- /dep.rs crate:dep
+#[non_exhaustive]
+pub struct UninhabitedStruct {
+ pub never: !,
+ // other fields
+}
+",
+ );
+ }
+
mod false_negatives {
//! The implementation of match checking here is a work in progress. As we roll this out, we
//! prefer false negatives to false positives (ideally there would be no false positives). This