diff options
| -rw-r--r-- | src/librustc_mir/hair/pattern/_match.rs | 26 | ||||
| -rw-r--r-- | src/librustc_mir/hair/pattern/check_match.rs | 9 |
2 files changed, 21 insertions, 14 deletions
diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index 08fcaf20d2c..8a6d007090a 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -238,7 +238,7 @@ use super::{FieldPat, Pat, PatKind, PatRange}; 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}; @@ -596,9 +596,21 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { } } - 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, } } @@ -858,8 +870,7 @@ impl<'tcx> Constructor<'tcx> { 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() @@ -1264,8 +1275,7 @@ fn all_constructors<'a, 'tcx>( // ``` // 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 @@ -2307,7 +2317,7 @@ fn specialize_one_pattern<'p, 'tcx>( 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(|_| { diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs index 737af3e1358..9a959cf3064 100644 --- a/src/librustc_mir/hair/pattern/check_match.rs +++ b/src/librustc_mir/hair/pattern/check_match.rs @@ -173,7 +173,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { 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 { @@ -186,15 +186,12 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { 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, |
