From d756f61a5a7ab84d58fdaa9d53d84f6dad29f8db Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Wed, 9 Nov 2016 17:55:57 +0800 Subject: [PATCH] Make is_uninhabited respect privacy --- src/librustc/ty/mod.rs | 14 ++++++++++---- src/librustc/ty/sty.rs | 19 ++++++++++--------- src/librustc_const_eval/check_match.rs | 2 +- 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index f4a9087641851..88eb4ec1014cb 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1394,13 +1394,16 @@ impl<'a, 'gcx, 'tcx> AdtDefData<'tcx, 'static> { #[inline] pub fn is_uninhabited_recurse(&'tcx self, visited: &mut HashMap<(DefId, &'tcx Substs<'tcx>), ()>, + block: Option, cx: TyCtxt<'a, 'gcx, 'tcx>, substs: &'tcx Substs<'tcx>) -> bool { match visited.entry((self.did, substs)) { hash_map::Entry::Occupied(_) => return false, hash_map::Entry::Vacant(ve) => ve.insert(()), }; - self.variants.iter().all(|v| v.is_uninhabited_recurse(visited, cx, substs, self.is_union())) + self.variants.iter().all(|v| { + v.is_uninhabited_recurse(visited, block, cx, substs, self.is_union()) + }) } } @@ -1809,13 +1812,14 @@ impl<'a, 'gcx, 'tcx> VariantDefData<'tcx, 'static> { #[inline] pub fn is_uninhabited_recurse(&'tcx self, visited: &mut HashMap<(DefId, &'tcx Substs<'tcx>), ()>, + block: Option, cx: TyCtxt<'a, 'gcx, 'tcx>, substs: &'tcx Substs<'tcx>, is_union: bool) -> bool { if is_union { - self.fields.iter().all(|f| f.is_uninhabited_recurse(visited, cx, substs)) + self.fields.iter().all(|f| f.is_uninhabited_recurse(visited, block, cx, substs)) } else { - self.fields.iter().any(|f| f.is_uninhabited_recurse(visited, cx, substs)) + self.fields.iter().any(|f| f.is_uninhabited_recurse(visited, block, cx, substs)) } } } @@ -1849,9 +1853,11 @@ impl<'a, 'gcx, 'tcx> FieldDefData<'tcx, 'static> { #[inline] pub fn is_uninhabited_recurse(&'tcx self, visited: &mut HashMap<(DefId, &'tcx Substs<'tcx>), ()>, + block: Option, tcx: TyCtxt<'a, 'gcx, 'tcx>, substs: &'tcx Substs<'tcx>) -> bool { - self.ty(tcx, substs).is_uninhabited_recurse(visited, tcx) + block.map_or(true, |b| self.vis.is_accessible_from(b, &tcx.map)) && + self.ty(tcx, substs).is_uninhabited_recurse(visited, block, tcx) } } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 39461dc4f74f5..4e54e3a3630dd 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -23,7 +23,7 @@ use std::fmt; use std::ops; use std::collections::HashMap; use syntax::abi; -use syntax::ast::{self, Name}; +use syntax::ast::{self, Name, NodeId}; use syntax::symbol::{keywords, InternedString}; use serialize; @@ -930,25 +930,26 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } - pub fn is_uninhabited(&self, cx: TyCtxt<'a, 'gcx, 'tcx>) -> bool { + /// Checks whether a type is uninhabited. + /// If `block` is `Some(id)` it also checks that the uninhabited-ness is visible from `id`. + pub fn is_uninhabited(&self, block: Option, cx: TyCtxt<'a, 'gcx, 'tcx>) -> bool { let mut visited = HashMap::new(); - self.is_uninhabited_recurse(&mut visited, cx) + self.is_uninhabited_recurse(&mut visited, block, cx) } pub fn is_uninhabited_recurse(&self, visited: &mut HashMap<(DefId, &'tcx Substs<'tcx>), ()>, + block: Option, cx: TyCtxt<'a, 'gcx, 'tcx>) -> bool { - // FIXME(#24885): be smarter here, the AdtDefData::is_empty method could easily be made - // more complete. match self.sty { TyAdt(def, substs) => { - def.is_uninhabited_recurse(visited, cx, substs) + def.is_uninhabited_recurse(visited, block, cx, substs) }, TyNever => true, - TyTuple(ref tys) => tys.iter().any(|ty| ty.is_uninhabited_recurse(visited, cx)), - TyArray(ty, len) => len > 0 && ty.is_uninhabited_recurse(visited, cx), - TyRef(_, ref tm) => tm.ty.is_uninhabited_recurse(visited, cx), + TyTuple(ref tys) => tys.iter().any(|ty| ty.is_uninhabited_recurse(visited, block, cx)), + TyArray(ty, len) => len > 0 && ty.is_uninhabited_recurse(visited, block, cx), + TyRef(_, ref tm) => tm.ty.is_uninhabited_recurse(visited, block, cx), _ => false, } diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index f63a27e0d7563..3c94d7d6fd5d1 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -204,7 +204,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { // Check for empty enum, because is_useful only works on inhabited types. let pat_ty = self.tcx.tables().node_id_to_type(scrut.id); if inlined_arms.is_empty() { - if !pat_ty.is_uninhabited(self.tcx) { + if !pat_ty.is_uninhabited(Some(scrut.id), self.tcx) { // We know the type is inhabited, so this must be wrong let mut err = create_e0004(self.tcx.sess, span, format!("non-exhaustive patterns: type {} \