use ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid};
use ty::TypeVariants::*;
use ty::layout::{Layout, TargetDataLayout};
-use ty::inhabitedness::DefIdForest;
use ty::maps;
use ty::steal::Steal;
use ty::BindingMode;
// FIXME dep tracking -- should be harmless enough
pub normalized_cache: RefCell<FxHashMap<Ty<'tcx>, Ty<'tcx>>>,
- pub inhabitedness_cache: RefCell<FxHashMap<Ty<'tcx>, DefIdForest>>,
-
/// Caches the results of trait selection. This cache is used
/// for things that do not have to do with the parameters in scope.
pub selection_cache: traits::SelectionCache<'tcx>,
mir_passes,
rcache: RefCell::new(FxHashMap()),
normalized_cache: RefCell::new(FxHashMap()),
- inhabitedness_cache: RefCell::new(FxHashMap()),
selection_cache: traits::SelectionCache::new(),
evaluation_cache: traits::EvaluationCache::new(),
rvalue_promotable_to_static: RefCell::new(NodeMap()),
/// This code should only compile in modules where the uninhabitedness of Foo is
/// visible.
pub fn is_ty_uninhabited_from(self, module: DefId, ty: Ty<'tcx>) -> bool {
- let forest = ty.uninhabited_from(&mut FxHashMap(), self);
-
// 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(self, module)
+ self.ty_inhabitedness_forest(ty).contains(self, module)
+ }
+
+ fn ty_inhabitedness_forest(self, ty: Ty<'tcx>) -> DefIdForest {
+ ty.uninhabited_from(&mut FxHashMap(), self)
}
pub fn is_enum_variant_uninhabited_from(self,
substs: &'tcx Substs<'tcx>)
-> bool
{
- let adt_kind = AdtKind::Enum;
- variant.uninhabited_from(&mut FxHashMap(), self, substs, adt_kind).contains(self, module)
+ self.variant_inhabitedness_forest(variant, substs).contains(self, module)
}
pub fn is_variant_uninhabited_from_all_modules(self,
variant: &'tcx VariantDef,
- substs: &'tcx Substs<'tcx>,
- adt_kind: AdtKind)
+ substs: &'tcx Substs<'tcx>)
-> bool
{
- !variant.uninhabited_from(&mut FxHashMap(), self, substs, adt_kind).is_empty()
+ !self.variant_inhabitedness_forest(variant, substs).is_empty()
+ }
+
+ fn variant_inhabitedness_forest(self, variant: &'tcx VariantDef, substs: &'tcx Substs<'tcx>)
+ -> DefIdForest {
+ // Determine the ADT kind:
+ let adt_def_id = self.adt_def_id_of_variant(variant);
+ let adt_kind = self.adt_def(adt_def_id).adt_kind();
+
+ // Compute inhabitedness forest:
+ variant.uninhabited_from(&mut FxHashMap(), self, substs, adt_kind)
}
}
&self,
visited: &mut FxHashMap<DefId, FxHashSet<&'tcx Substs<'tcx>>>,
tcx: TyCtxt<'a, 'gcx, 'tcx>) -> DefIdForest
- {
- match tcx.lift_to_global(&self) {
- Some(global_ty) => {
- {
- let cache = tcx.inhabitedness_cache.borrow();
- if let Some(forest) = cache.get(&global_ty) {
- return forest.clone();
- }
- }
- let forest = global_ty.uninhabited_from_inner(visited, tcx);
- let mut cache = tcx.inhabitedness_cache.borrow_mut();
- cache.insert(global_ty, forest.clone());
- forest
- },
- None => {
- let forest = self.uninhabited_from_inner(visited, tcx);
- forest
- },
- }
- }
-
- fn uninhabited_from_inner(
- &self,
- visited: &mut FxHashMap<DefId, FxHashSet<&'tcx Substs<'tcx>>>,
- tcx: TyCtxt<'a, 'gcx, 'tcx>) -> DefIdForest
{
match self.sty {
TyAdt(def, substs) => {
use hir::{map as hir_map, FreevarMap, TraitMap};
use hir::def::{Def, CtorKind, ExportMap};
use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
+use hir::map::DefPathData;
use ich::StableHashingContext;
use middle::const_val::ConstVal;
use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
}
}
+ /// Given a `VariantDef`, returns the def-id of the `AdtDef` of which it is a part.
+ pub fn adt_def_id_of_variant(self, variant_def: &'tcx VariantDef) -> DefId {
+ let def_key = self.def_key(variant_def.did);
+ match def_key.disambiguated_data.data {
+ // for enum variants and tuple structs, the def-id of the ADT itself
+ // is the *parent* of the variant
+ DefPathData::EnumVariant(..) | DefPathData::StructCtor =>
+ DefId { krate: variant_def.did.krate, index: def_key.parent.unwrap() },
+
+ // otherwise, for structs and unions, they share a def-id
+ _ => variant_def.did,
+ }
+ }
+
pub fn item_name(self, id: DefId) -> InternedString {
if let Some(id) = self.hir.as_local_node_id(id) {
self.hir.name(id).as_str()
if self.hir.tcx().sess.features.borrow().never_type {
let irrefutable = adt_def.variants.iter().enumerate().all(|(i, v)| {
i == variant_index || {
- let adt_kind = adt_def.adt_kind();
- self.hir.tcx().is_variant_uninhabited_from_all_modules(v,
- substs,
- adt_kind)
+ self.hir.tcx().is_variant_uninhabited_from_all_modules(v, substs)
}
});
if irrefutable {
--- /dev/null
+// Copyright 2016 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(never_type)]
+
+// Regression test for inhabitedness check. The old
+// cache used to cause us to incorrectly decide
+// that `test_b` was invalid.
+
+struct Foo {
+ field1: !,
+ field2: Option<&'static Bar>,
+}
+
+struct Bar {
+ field1: &'static Foo
+}
+
+fn test_a() {
+ let x: Option<Foo> = None;
+ match x { None => () }
+}
+
+fn test_b() {
+ let x: Option<Bar> = None;
+ match x { None => () }
+}
+
+fn main() { }