diff --git a/src/librustc_mir_build/hair/pattern/_match.rs b/src/librustc_mir_build/hair/pattern/_match.rs index 51ba84416d64d..8d7397a0027de 100644 --- a/src/librustc_mir_build/hair/pattern/_match.rs +++ b/src/librustc_mir_build/hair/pattern/_match.rs @@ -242,7 +242,7 @@ use rustc_hir::{HirId, RangeEnd}; use rustc_middle::mir::interpret::{truncate, AllocId, ConstValue, Pointer, Scalar}; use rustc_middle::mir::Field; use rustc_middle::ty::layout::IntegerExt; -use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeFoldable, VariantDef}; +use rustc_middle::ty::{self, Const, FieldDef, Ty, TyCtxt, TypeFoldable, VariantDef}; use rustc_session::lint; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{Integer, Size, VariantIdx}; @@ -602,7 +602,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { } } - // Returns whether the given type is an enum from another crate declared `#[non_exhaustive]`. + /// Returns whether the given type is an enum from another crate declared `#[non_exhaustive]`. crate fn is_foreign_non_exhaustive_enum(&self, ty: Ty<'tcx>) -> bool { match ty.kind { ty::Adt(def, ..) => { @@ -612,14 +612,35 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { } } - // Returns whether the given variant is from another crate and has its fields declared - // `#[non_exhaustive]`. + /// 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, } } + + /// In the cases of either a `#[non_exhaustive]` field list or a non-public field, we hide + /// uninhabited fields in order not to reveal the uninhabitedness of the whole variant. + fn hide_uninhabited_field( + &self, + adt_ty: Ty<'tcx>, + variant: &VariantDef, + field: &FieldDef, + ) -> bool { + match adt_ty.kind { + ty::Adt(adt, substs) => { + let is_non_exhaustive = self.is_foreign_non_exhaustive_variant(adt_ty, variant); + let field_ty = field.ty(self.tcx, substs); + let is_visible = + adt.is_enum() || field.vis.is_accessible_from(self.module, self.tcx); + let is_uninhabited = self.is_uninhabited(field_ty); + is_uninhabited && (!is_visible || is_non_exhaustive) + } + _ => false, + } + } } #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -733,8 +754,8 @@ impl Slice { #[derive(Clone, Debug, PartialEq)] enum Constructor<'tcx> { - /// The constructor of all patterns that don't vary by constructor, - /// e.g., struct patterns and fixed-length arrays. + /// The constructor for patterns that have a single constructor, like tuples, struct patterns + /// and fixed-length arrays. Single, /// Enum variants. Variant(DefId), @@ -881,38 +902,16 @@ 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 = cx.is_foreign_non_exhaustive_variant(ty, variant); variant .fields .iter() .map(|field| { - let is_visible = adt.is_enum() - || field.vis.is_accessible_from(cx.module, cx.tcx); - let is_uninhabited = cx.is_uninhabited(field.ty(cx.tcx, substs)); - match (is_visible, is_non_exhaustive, is_uninhabited) { - // Treat all uninhabited types in non-exhaustive variants as - // `TyErr`. - (_, true, true) => cx.tcx.types.err, - // Treat all non-visible fields as `TyErr`. They can't appear - // in any other pattern from this match (because they are - // private), so their type does not matter - but we don't want - // to know they are uninhabited. - (false, ..) => cx.tcx.types.err, - (true, ..) => { - let ty = field.ty(cx.tcx, substs); - match ty.kind { - // If the field type returned is an array of an unknown - // size return an TyErr. - ty::Array(_, len) - if len - .try_eval_usize(cx.tcx, cx.param_env) - .is_none() => - { - cx.tcx.types.err - } - _ => ty, - } - } + // Treat hidden fields as TyErr so we don't know they are + // uninhabited. + if cx.hide_uninhabited_field(ty, variant, field) { + cx.tcx.types.err + } else { + field.ty(cx.tcx, substs) } }) .map(Pat::wildcard_from_ty) @@ -2360,12 +2359,17 @@ fn specialize_one_pattern<'p, 'tcx>( PatKind::Variant { adt_def, variant_index, ref subpatterns, .. } => { let variant = &adt_def.variants[variant_index]; - 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(|_| { - patterns_for_variant(cx, subpatterns, ctor_wild_subpatterns, is_non_exhaustive) - }) + if constructor == &Variant(variant.def_id) { + let is_non_exhaustive = cx.is_foreign_non_exhaustive_variant(pat.ty, variant); + Some(patterns_for_variant( + cx, + subpatterns, + ctor_wild_subpatterns, + is_non_exhaustive, + )) + } else { + None + } } PatKind::Leaf { ref subpatterns } => { diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 1acbcc038891d..035e5880dc522 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -178,7 +178,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match expected_ty.kind { ty::Dynamic(ref object_type, ..) => { let sig = object_type.projection_bounds().find_map(|pb| { - let pb = pb.with_self_ty(self.tcx, self.tcx.types.err); + let pb = pb.with_self_ty(self.tcx, self.tcx.types.trait_object_dummy_self); self.deduce_sig_from_projection(None, &pb) }); let kind = object_type