From d6482510f4ac179506370f421b2c3a3802f574f9 Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Wed, 14 Sep 2016 23:58:58 +0800 Subject: [PATCH] Expand `is_uninhabited` to recurse into datatypes --- src/librustc/ty/mod.rs | 45 +++++++++++++++++++++++++++++++++++++----- src/librustc/ty/sty.rs | 15 ++++++++++++-- 2 files changed, 53 insertions(+), 7 deletions(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index e94e93158c4..5737f776422 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -16,6 +16,7 @@ pub use self::IntVarValue::*; pub use self::LvaluePreference::*; pub use self::fold::TypeFoldable; +use std::collections::{hash_map, HashMap}; use dep_graph::{self, DepNode}; use hir::map as ast_map; use middle; @@ -1389,6 +1390,20 @@ impl<'tcx> serialize::UseSpecializedEncodable for AdtDef<'tcx> { impl<'tcx> serialize::UseSpecializedDecodable for AdtDef<'tcx> {} +impl<'a, 'gcx, 'tcx> AdtDefData<'tcx, 'static> { + #[inline] + pub fn is_uninhabited_recurse(&'tcx self, + visited: &mut HashMap<(DefId, &'tcx Substs<'tcx>), ()>, + cx: TyCtxt<'a, 'gcx, 'tcx>, + substs: &'tcx Substs<'tcx>) -> bool { + match visited.entry((self.did, substs)) { + hash_map::Entry::Occupied(_) => return true, + hash_map::Entry::Vacant(ve) => ve.insert(()), + }; + self.variants.iter().all(|v| v.is_uninhabited_recurse(visited, cx, substs, self.is_union())) + } +} + #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum AdtKind { Struct, Union, Enum } @@ -1531,11 +1546,6 @@ impl<'a, 'gcx, 'tcx, 'container> AdtDefData<'gcx, 'container> { self.variants.iter().flat_map(VariantDefData::fields_iter) } - #[inline] - pub fn is_empty(&self) -> bool { - self.variants.is_empty() - } - #[inline] pub fn is_univariant(&self) -> bool { self.variants.len() == 1 @@ -1795,6 +1805,21 @@ impl<'tcx, 'container> VariantDefData<'tcx, 'container> { } } +impl<'a, 'gcx, 'tcx> VariantDefData<'tcx, 'static> { + #[inline] + pub fn is_uninhabited_recurse(&'tcx self, + visited: &mut HashMap<(DefId, &'tcx Substs<'tcx>), ()>, + 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)) + } else { + self.fields.iter().any(|f| f.is_uninhabited_recurse(visited, cx, substs)) + } + } +} + impl<'a, 'gcx, 'tcx, 'container> FieldDefData<'tcx, 'container> { pub fn new(did: DefId, name: Name, @@ -1820,6 +1845,16 @@ impl<'a, 'gcx, 'tcx, 'container> FieldDefData<'tcx, 'container> { } } +impl<'a, 'gcx, 'tcx> FieldDefData<'tcx, 'static> { + #[inline] + pub fn is_uninhabited_recurse(&'tcx self, + visited: &mut HashMap<(DefId, &'tcx Substs<'tcx>), ()>, + tcx: TyCtxt<'a, 'gcx, 'tcx>, + substs: &'tcx Substs<'tcx>) -> bool { + self.ty(tcx, substs).is_uninhabited_recurse(visited, tcx) + } +} + /// Records the substitutions used to translate the polytype for an /// item into the monotype of an item reference. #[derive(Clone, RustcEncodable, RustcDecodable)] diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index af45a323eee..53230eaf59d 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -21,6 +21,7 @@ use util::common::ErrorReported; use collections::enum_set::{self, EnumSet, CLike}; use std::fmt; use std::ops; +use std::collections::HashMap; use syntax::abi; use syntax::ast::{self, Name}; use syntax::symbol::{keywords, InternedString}; @@ -929,14 +930,24 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } - pub fn is_uninhabited(&self, cx: TyCtxt) -> bool { + pub fn is_uninhabited(&self, cx: TyCtxt<'a, 'gcx, 'tcx>) -> bool { + let mut visited = HashMap::new(); + self.is_uninhabited_recurse(&mut visited, cx) + } + + pub fn is_uninhabited_recurse(&self, + visited: &mut HashMap<(DefId, &'tcx Substs<'tcx>), ()>, + 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, _) => def.is_empty(), + TyAdt(def, substs) => { + def.is_uninhabited_recurse(visited, cx, substs) + }, TyNever => true, TyTuple(ref tys) => tys.iter().any(|ty| ty.is_uninhabited(cx)), + TyArray(ty, len) => len > 0 && ty.is_uninhabited(cx), // FIXME(canndrew): this line breaks core::fmt //TyRef(_, ref tm) => tm.ty.is_uninhabited(cx),