Box field detection; test #[non-exhaustive] attribute

This commit is contained in:
Dawer 2021-05-12 11:04:56 +05:00
parent f46a42f73a
commit 4cce7a6407
3 changed files with 52 additions and 10 deletions

View File

@ -1090,6 +1090,42 @@ fn main() {
);
}
#[test]
fn enum_non_exhaustive() {
check_diagnostics(
r#"
//- /lib.rs crate:lib
#[non_exhaustive]
pub enum E { A, B }
fn _local() {
match E::A { _ => {} }
match E::A {
E::A => {}
E::B => {}
}
match E::A {
E::A | E::B => {}
}
}
//- /main.rs crate:main deps:lib
use lib::E;
fn main() {
match E::A { _ => {} }
match E::A {
//^^^^ Missing match arm
E::A => {}
E::B => {}
}
match E::A {
//^^^^ Missing match arm
E::A | E::B => {}
}
}
"#,
);
}
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

View File

@ -513,9 +513,7 @@ impl SplitWildcard {
if is_secretly_empty || is_declared_nonexhaustive {
smallvec![NonExhaustive]
} else if cx.feature_exhaustive_patterns() {
// If `exhaustive_patterns` is enabled, we exclude variants known to be
// uninhabited.
unhandled()
unimplemented!() // see MatchCheckCtx.feature_exhaustive_patterns()
} else {
enum_data
.variants
@ -643,6 +641,7 @@ impl Fields {
Fields::Vec(pats)
}
/// Creates a new list of wildcard fields for a given constructor.
pub(crate) fn wildcards(pcx: PatCtxt<'_>, constructor: &Constructor) -> Self {
let ty = pcx.ty;
let cx = pcx.cx;
@ -655,14 +654,13 @@ impl Fields {
Fields::wildcards_from_tys(cx, tys)
}
TyKind::Ref(.., rty) => Fields::from_single_pattern(wildcard_from_ty(rty)),
TyKind::Adt(AdtId(adt), substs) => {
let adt_is_box = false; // TODO(iDawer): implement this
if adt_is_box {
&TyKind::Adt(AdtId(adt), ref substs) => {
if adt_is_box(adt, cx) {
// Use T as the sub pattern type of Box<T>.
let subst_ty = substs.at(&Interner, 0).assert_ty_ref(&Interner);
Fields::from_single_pattern(wildcard_from_ty(subst_ty))
} else {
let variant_id = constructor.variant_id_for_adt(*adt);
let variant_id = constructor.variant_id_for_adt(adt);
let adt_is_local =
variant_id.module(cx.db.upcast()).krate() == cx.module.krate();
// Whether we must not match the fields of this variant exhaustively.
@ -680,7 +678,7 @@ impl Fields {
if has_no_hidden_fields {
Fields::wildcards_from_tys(cx, field_tys())
} else {
//FIXME(iDawer): see MatchCheckCtx::is_uninhabited
//FIXME(iDawer): see MatchCheckCtx::is_uninhabited, has_no_hidden_fields is always true
unimplemented!("exhaustive_patterns feature")
}
}
@ -892,3 +890,11 @@ fn is_field_list_non_exhaustive(variant_id: VariantId, cx: &MatchCheckCtx<'_>) -
};
cx.db.attrs(attr_def_id).by_key("non_exhaustive").exists()
}
fn adt_is_box(adt: hir_def::AdtId, cx: &MatchCheckCtx<'_>) -> bool {
use hir_def::lang_item::LangItemTarget;
match cx.db.lang_item(cx.module.krate(), "owned_box".into()) {
Some(LangItemTarget::StructId(box_id)) => adt == box_id.into(),
_ => false,
}
}

View File

@ -293,7 +293,7 @@ pub(crate) struct MatchCheckCtx<'a> {
pub(crate) match_expr: ExprId,
pub(crate) infer: &'a InferenceResult,
pub(crate) db: &'a dyn HirDatabase,
/// Lowered patterns from self.body.pats plus generated by the check.
/// Lowered patterns from arms plus generated by the check.
pub(crate) pattern_arena: &'a RefCell<PatternArena>,
}
@ -315,7 +315,7 @@ impl<'a> MatchCheckCtx<'a> {
// Rust feature described as "Allows exhaustive pattern matching on types that contain uninhabited types."
pub(super) fn feature_exhaustive_patterns(&self) -> bool {
// TODO
// FIXME see MatchCheckCtx::is_uninhabited
false
}