diff --git a/src/librustc/ty/inhabitedness/def_id_forest.rs b/src/librustc/ty/inhabitedness/def_id_forest.rs new file mode 100644 index 0000000000000..16bc65603f135 --- /dev/null +++ b/src/librustc/ty/inhabitedness/def_id_forest.rs @@ -0,0 +1,133 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::mem; +use rustc_data_structures::small_vec::SmallVec; +use syntax::ast::CRATE_NODE_ID; +use ty::context::TyCtxt; +use ty::{DefId, DefIdTree}; + +/// Represents a forest of DefIds closed under the ancestor relation. That is, +/// if a DefId representing a module is contained in the forest then all +/// DefIds defined in that module or submodules are also implicitly contained +/// in the forest. +/// +/// This is used to represent a set of modules in which a type is visibly +/// uninhabited. +#[derive(Clone)] +pub struct DefIdForest { + /// The minimal set of DefIds required to represent the whole set. + /// If A and B are DefIds in the DefIdForest, and A is a desecendant + /// of B, then only B will be in root_ids. + /// We use a SmallVec here because (for its use for cacheing inhabitedness) + /// its rare that this will contain even two ids. + root_ids: SmallVec<[DefId; 1]>, +} + +impl<'a, 'gcx, 'tcx> DefIdForest { + /// Create an empty forest. + pub fn empty() -> DefIdForest { + DefIdForest { + root_ids: SmallVec::new(), + } + } + + /// Create a forest consisting of a single tree representing the entire + /// crate. + #[inline] + pub fn full(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> DefIdForest { + let crate_id = tcx.map.local_def_id(CRATE_NODE_ID); + DefIdForest::from_id(crate_id) + } + + /// Create a forest containing a DefId and all its descendants. + pub fn from_id(id: DefId) -> DefIdForest { + let mut root_ids = SmallVec::new(); + root_ids.push(id); + DefIdForest { + root_ids: root_ids, + } + } + + /// Test whether the forest is empty. + pub fn is_empty(&self) -> bool { + self.root_ids.is_empty() + } + + /// Test whether the forest conains a given DefId. + pub fn contains(&self, + tcx: TyCtxt<'a, 'gcx, 'tcx>, + id: DefId) -> bool + { + for root_id in self.root_ids.iter() { + if tcx.is_descendant_of(id, *root_id) { + return true; + } + } + false + } + + /// Calculate the intersection of a collection of forests. + pub fn intersection(tcx: TyCtxt<'a, 'gcx, 'tcx>, + iter: I) -> DefIdForest + where I: IntoIterator + { + let mut ret = DefIdForest::full(tcx); + let mut next_ret = SmallVec::new(); + let mut old_ret: SmallVec<[DefId; 1]> = SmallVec::new(); + for next_forest in iter { + for id in ret.root_ids.drain(..) { + if next_forest.contains(tcx, id) { + next_ret.push(id); + } else { + old_ret.push(id); + } + } + ret.root_ids.extend(old_ret.drain(..)); + + for id in next_forest.root_ids { + if ret.contains(tcx, id) { + next_ret.push(id); + } + } + + mem::swap(&mut next_ret, &mut ret.root_ids); + next_ret.drain(..); + } + ret + } + + /// Calculate the union of a collection of forests. + pub fn union(tcx: TyCtxt<'a, 'gcx, 'tcx>, + iter: I) -> DefIdForest + where I: IntoIterator + { + let mut ret = DefIdForest::empty(); + let mut next_ret = SmallVec::new(); + for next_forest in iter { + for id in ret.root_ids.drain(..) { + if !next_forest.contains(tcx, id) { + next_ret.push(id); + } + } + + for id in next_forest.root_ids { + if !next_ret.contains(&id) { + next_ret.push(id); + } + } + + mem::swap(&mut next_ret, &mut ret.root_ids); + next_ret.drain(..); + } + ret + } +} + diff --git a/src/librustc/ty/inhabitedness.rs b/src/librustc/ty/inhabitedness/mod.rs similarity index 59% rename from src/librustc/ty/inhabitedness.rs rename to src/librustc/ty/inhabitedness/mod.rs index 762fb11ba05e9..1cc31b20ba95d 100644 --- a/src/librustc/ty/inhabitedness.rs +++ b/src/librustc/ty/inhabitedness/mod.rs @@ -8,127 +8,59 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::mem; -use rustc_data_structures::small_vec::SmallVec; -use syntax::ast::CRATE_NODE_ID; use util::nodemap::FxHashSet; use ty::context::TyCtxt; use ty::{AdtDef, VariantDef, FieldDef, TyS}; use ty::{DefId, Substs}; -use ty::{AdtKind, Visibility, DefIdTree}; +use ty::{AdtKind, Visibility}; use ty::TypeVariants::*; -/// Represents a set of DefIds closed under the ancestor relation. That is, if -/// a DefId is in this set then so are all its descendants. -#[derive(Clone)] -pub struct DefIdForest { - /// The minimal set of DefIds required to represent the whole set. - /// If A and B are DefIds in the DefIdForest, and A is a desecendant - /// of B, then only B will be in root_ids. - /// We use a SmallVec here because (for its use in this module) its rare - /// that this will contain even two ids. - root_ids: SmallVec<[DefId; 1]>, -} - -impl<'a, 'gcx, 'tcx> DefIdForest { - /// Create an empty forest. - pub fn empty() -> DefIdForest { - DefIdForest { - root_ids: SmallVec::new(), - } - } - - /// Create a forest consisting of a single tree representing the entire - /// crate. - #[inline] - pub fn full(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> DefIdForest { - let crate_id = tcx.map.local_def_id(CRATE_NODE_ID); - DefIdForest::from_id(crate_id) - } - - /// Create a forest containing a DefId and all its descendants. - pub fn from_id(id: DefId) -> DefIdForest { - let mut root_ids = SmallVec::new(); - root_ids.push(id); - DefIdForest { - root_ids: root_ids, - } - } - - /// Test whether the forest is empty. - pub fn is_empty(&self) -> bool { - self.root_ids.is_empty() - } - - /// Test whether the forest conains a given DefId. - pub fn contains(&self, - tcx: TyCtxt<'a, 'gcx, 'tcx>, - id: DefId) -> bool - { - for root_id in self.root_ids.iter() { - if tcx.is_descendant_of(id, *root_id) { - return true; - } - } - false - } - - /// Calculate the intersection of a collection of forests. - pub fn intersection(tcx: TyCtxt<'a, 'gcx, 'tcx>, - iter: I) -> DefIdForest - where I: IntoIterator - { - let mut ret = DefIdForest::full(tcx); - let mut next_ret = SmallVec::new(); - let mut old_ret: SmallVec<[DefId; 1]> = SmallVec::new(); - for next_forest in iter { - for id in ret.root_ids.drain(..) { - if next_forest.contains(tcx, id) { - next_ret.push(id); - } else { - old_ret.push(id); - } - } - ret.root_ids.extend(old_ret.drain(..)); +pub use self::def_id_forest::DefIdForest; - for id in next_forest.root_ids { - if ret.contains(tcx, id) { - next_ret.push(id); - } - } - - mem::swap(&mut next_ret, &mut ret.root_ids); - next_ret.drain(..); - } - ret - } +mod def_id_forest; - /// Calculate the union of a collection of forests. - pub fn union(tcx: TyCtxt<'a, 'gcx, 'tcx>, - iter: I) -> DefIdForest - where I: IntoIterator - { - let mut ret = DefIdForest::empty(); - let mut next_ret = SmallVec::new(); - for next_forest in iter { - for id in ret.root_ids.drain(..) { - if !next_forest.contains(tcx, id) { - next_ret.push(id); - } - } - - for id in next_forest.root_ids { - if !next_ret.contains(&id) { - next_ret.push(id); - } - } - - mem::swap(&mut next_ret, &mut ret.root_ids); - next_ret.drain(..); - } - ret - } -} +// The methods in this module calculate DefIdForests of modules in which a +// AdtDef/VariantDef/FieldDef is visibly uninhabited. +// +// # Example +// ```rust +// enum Void {} +// mod a { +// pub mod b { +// pub struct SecretlyUninhabited { +// _priv: !, +// } +// } +// } +// +// mod c { +// pub struct AlsoSecretlyUninhabited { +// _priv: Void, +// } +// mod d { +// } +// } +// +// struct Foo { +// x: a::b::SecretlyUninhabited, +// y: c::AlsoSecretlyUninhabited, +// } +// ``` +// In this code, the type Foo will only be visibly uninhabited inside the +// modules b, c and d. Calling uninhabited_from on Foo or its AdtDef will +// return the forest of modules {b, c->d} (represented in a DefIdForest by the +// set {b, c}) +// +// We need this information for pattern-matching on Foo or types that contain +// Foo. +// +// # Example +// ```rust +// let foo_result: Result = ... ; +// let Ok(t) = foo_result; +// ``` +// This code should only compile in modules where the uninhabitedness of Foo is +// visible. impl<'a, 'gcx, 'tcx> AdtDef { /// Calculate the forest of DefIds from which this adt is visibly uninhabited. @@ -189,6 +121,9 @@ impl<'a, 'gcx, 'tcx> FieldDef { is_enum: bool) -> DefIdForest { let mut data_uninhabitedness = move || self.ty(tcx, substs).uninhabited_from(visited, tcx); + // FIXME(canndrew): Currently enum fields are (incorrectly) stored with + // Visibility::Invisible so we need to override self.vis if we're + // dealing with an enum. if is_enum { data_uninhabitedness() } else { diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 1890bb4335aac..319b11d8031e9 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -980,20 +980,51 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } /// Checks whether a type is visibly uninhabited from a particular module. + /// # Example + /// ```rust + /// enum Void {} + /// mod a { + /// pub mod b { + /// pub struct SecretlyUninhabited { + /// _priv: !, + /// } + /// } + /// } + /// + /// mod c { + /// pub struct AlsoSecretlyUninhabited { + /// _priv: Void, + /// } + /// mod d { + /// } + /// } + /// + /// struct Foo { + /// x: a::b::SecretlyUninhabited, + /// y: c::AlsoSecretlyUninhabited, + /// } + /// ``` + /// In this code, the type `Foo` will only be visibly uninhabited inside the + /// modules b, c and d. This effects pattern-matching on `Foo` or types that + /// contain `Foo`. + /// + /// # Example + /// ```rust + /// let foo_result: Result = ... ; + /// let Ok(t) = foo_result; + /// ``` + /// This code should only compile in modules where the uninhabitedness of Foo is + /// visible. pub fn is_uninhabited_from(&self, module: DefId, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> bool { let mut visited = FxHashSet::default(); let forest = self.uninhabited_from(&mut visited, tcx); - forest.contains(tcx, module) - } - /// Checks whether a type is uninhabited. - /// Note: just because a type is uninhabited, that doesn't mean that it's - /// *visibly* uninhabited outside its module. You sometimes may want - /// `is_uninhabited_from` instead. - pub fn is_uninhabited_anywhere(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> bool { - let mut visited = FxHashSet::default(); - let node_set = self.uninhabited_from(&mut visited, tcx); - !node_set.is_empty() + // To check whether this type is uninhabited at all (not just from the + // given node) you could check whether the forest is empty. + // ``` + // forest.is_empty() + // ``` + forest.contains(tcx, module) } pub fn is_primitive(&self) -> bool {