use rustc::hir::def_id::DefId;
use rustc::hir::{HirId, RangeEnd};
use rustc::ty::layout::{Integer, IntegerExt, Size, VariantIdx};
-use rustc::ty::{self, Const, Ty, TyCtxt, TypeFoldable};
+use rustc::ty::{self, Const, Ty, TyCtxt, TypeFoldable, VariantDef};
use rustc::lint;
use rustc::mir::interpret::{truncate, AllocId, ConstValue, Pointer, Scalar};
}
}
- fn is_local(&self, ty: Ty<'tcx>) -> bool {
+ // Returns whether the given type is an enum from another crate declared `#[non_exhaustive]`.
+ pub fn is_foreign_non_exhaustive_enum(&self, ty: Ty<'tcx>) -> bool {
match ty.kind {
- ty::Adt(adt_def, ..) => adt_def.did.is_local(),
+ ty::Adt(def, ..) => {
+ def.is_enum() && def.is_variant_list_non_exhaustive() && !def.did.is_local()
+ }
+ _ => false,
+ }
+ }
+
+ // Returns whether the given variant is from another crate and has its fields declared
+ // `#[non_exhaustive]`.
+ fn is_foreign_non_exhaustive_variant(&self, ty: Ty<'tcx>, variant: &VariantDef) -> bool {
+ match ty.kind {
+ ty::Adt(def, ..) => variant.is_field_list_non_exhaustive() && !def.did.is_local(),
_ => false,
}
}
vec![Pat::wildcard_from_ty(substs.type_at(0))]
} else {
let variant = &adt.variants[self.variant_index_for_adt(cx, adt)];
- let is_non_exhaustive =
- variant.is_field_list_non_exhaustive() && !cx.is_local(ty);
+ let is_non_exhaustive = cx.is_foreign_non_exhaustive_variant(ty, variant);
variant
.fields
.iter()
// ```
// we don't want to show every possible IO error, but instead have only `_` as the
// witness.
- let is_declared_nonexhaustive =
- def.is_variant_list_non_exhaustive() && !cx.is_local(pcx.ty);
+ let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive_enum(pcx.ty);
// If `exhaustive_patterns` is disabled and our scrutinee is an empty enum, we treat it
// as though it had an "unknown" constructor to avoid exposing its emptyness. Note that
PatKind::Variant { adt_def, variant_index, ref subpatterns, .. } => {
let ref variant = adt_def.variants[variant_index];
- let is_non_exhaustive = variant.is_field_list_non_exhaustive() && !cx.is_local(pat.ty);
+ let is_non_exhaustive = cx.is_foreign_non_exhaustive_variant(pat.ty, variant);
Some(Variant(variant.def_id))
.filter(|variant_constructor| variant_constructor == constructor)
.map(|_| {
let mut def_span = None;
let mut missing_variants = vec![];
if inlined_arms.is_empty() {
- let scrutinee_is_uninhabited = if self.tcx.features().exhaustive_patterns {
+ let scrutinee_is_visibly_uninhabited = if self.tcx.features().exhaustive_patterns {
self.tcx.is_ty_uninhabited_from(module, pat_ty)
} else {
match pat_ty.kind {
def.variants.iter().map(|variant| variant.ident).collect();
}
- let is_non_exhaustive_and_non_local =
- def.is_variant_list_non_exhaustive() && !def.did.is_local();
-
- !(is_non_exhaustive_and_non_local) && def.variants.is_empty()
+ def.variants.is_empty() && !cx.is_foreign_non_exhaustive_enum(pat_ty)
}
_ => false,
}
};
- if !scrutinee_is_uninhabited {
+ if !scrutinee_is_visibly_uninhabited {
// We know the type is inhabited, so this must be wrong
let mut err = create_e0004(
self.tcx.sess,