Skip to content

fix: Non-exhaustive structs may be empty #18645

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Merged
merged 1 commit into from
Dec 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 1 addition & 5 deletions crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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()
Expand Down
8 changes: 1 addition & 7 deletions crates/hir-ty/src/inhabitedness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down Expand Up @@ -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() {
Expand Down
19 changes: 19 additions & 0 deletions crates/ide-diagnostics/src/handlers/missing_match_arms.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading