mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 21:13:37 +00:00
fix: Non-exhaustive structs may be empty
This commit is contained in:
parent
1c3043bc8c
commit
55a7ee8065
3 changed files with 21 additions and 12 deletions
|
@ -383,9 +383,6 @@ impl<'db> PatCx for MatchCheckCtx<'db> {
|
||||||
} else {
|
} else {
|
||||||
let variant = Self::variant_id_for_adt(self.db, ctor, adt).unwrap();
|
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));
|
let visibilities = LazyCell::new(|| self.db.field_visibilities(variant));
|
||||||
|
|
||||||
self.list_variant_fields(ty, 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)
|
.is_visible_from(self.db.upcast(), self.module)
|
||||||
};
|
};
|
||||||
let is_uninhabited = self.is_uninhabited(&ty);
|
let is_uninhabited = self.is_uninhabited(&ty);
|
||||||
let private_uninhabited =
|
let private_uninhabited = is_uninhabited && !is_visible();
|
||||||
is_uninhabited && (!is_visible() || *is_non_exhaustive);
|
|
||||||
(ty, PrivateUninhabitedField(private_uninhabited))
|
(ty, PrivateUninhabitedField(private_uninhabited))
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
|
|
|
@ -5,8 +5,7 @@ use chalk_ir::{
|
||||||
visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor},
|
visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor},
|
||||||
DebruijnIndex,
|
DebruijnIndex,
|
||||||
};
|
};
|
||||||
use hir_def::{visibility::Visibility, AdtId, EnumVariantId, HasModule, ModuleId, VariantId};
|
use hir_def::{visibility::Visibility, AdtId, EnumVariantId, ModuleId, VariantId};
|
||||||
use intern::sym;
|
|
||||||
use rustc_hash::FxHashSet;
|
use rustc_hash::FxHashSet;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -118,11 +117,6 @@ impl UninhabitedFrom<'_> {
|
||||||
variant: VariantId,
|
variant: VariantId,
|
||||||
subst: &Substitution,
|
subst: &Substitution,
|
||||||
) -> ControlFlow<VisiblyUninhabited> {
|
) -> 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 variant_data = self.db.variant_data(variant);
|
||||||
let fields = variant_data.fields();
|
let fields = variant_data.fields();
|
||||||
if fields.is_empty() {
|
if fields.is_empty() {
|
||||||
|
|
|
@ -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 {
|
mod false_negatives {
|
||||||
//! The implementation of match checking here is a work in progress. As we roll this out, we
|
//! 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
|
//! prefer false negatives to false positives (ideally there would be no false positives). This
|
||||||
|
|
Loading…
Reference in a new issue