]> git.lizzy.rs Git - rust.git/commitdiff
Factor out some `non_exhaustive`-related checks
authorNadrieril <nadrieril+git@gmail.com>
Sat, 30 Nov 2019 16:00:44 +0000 (16:00 +0000)
committerNadrieril <nadrieril+git@gmail.com>
Wed, 4 Dec 2019 16:43:21 +0000 (16:43 +0000)
src/librustc_mir/hair/pattern/_match.rs
src/librustc_mir/hair/pattern/check_match.rs

index 08fcaf20d2cc8edc50cdafe03224aabb4cff1a86..8a6d007090a2a0644902357680449a6d2c63d618 100644 (file)
 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 @@ fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool {
         }
     }
 
-    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 @@ fn wildcard_subpatterns<'a>(
                         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(|_| {
index 737af3e1358f4593924610c8f8b7f50b6f64b67e..9a959cf306432071be2ed44f18bd11df4a7ede0b 100644 (file)
@@ -173,7 +173,7 @@ fn check_match(&mut self, scrut: &hir::Expr, arms: &'tcx [hir::Arm], source: hir
             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 @@ fn check_match(&mut self, scrut: &hir::Expr, arms: &'tcx [hir::Arm], source: hir
                                     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,