diff --git a/src/librustc/dep_graph/dep_tracking_map.rs b/src/librustc/dep_graph/dep_tracking_map.rs index 2ffc3951cc94d..9f45e66f0d937 100644 --- a/src/librustc/dep_graph/dep_tracking_map.rs +++ b/src/librustc/dep_graph/dep_tracking_map.rs @@ -11,6 +11,7 @@ use hir::def_id::DefId; use rustc_data_structures::fx::FxHashMap; use std::cell::RefCell; +use std::collections::hash_map::Entry; use std::ops::Index; use std::hash::Hash; use std::marker::PhantomData; @@ -67,6 +68,11 @@ impl DepTrackingMap { assert!(old_value.is_none()); } + pub fn entry(&mut self, k: M::Key) -> Entry { + self.write(&k); + self.map.entry(k) + } + pub fn contains_key(&self, k: &M::Key) -> bool { self.read(k); self.map.contains_key(k) diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index ce4d1f5ec974c..26c92e3e7ecf7 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -13,10 +13,9 @@ use hir::def_id::{CrateNum, DefId}; use middle::const_val::ConstVal; use mir; use ty::{self, Ty, TyCtxt}; -use util::common::MemoizationMap; use rustc_data_structures::indexed_vec::IndexVec; -use std::cell::RefCell; +use std::cell::{RefCell, RefMut}; use std::rc::Rc; use syntax_pos::{Span, DUMMY_SP}; @@ -66,8 +65,13 @@ impl<'tcx> Value<'tcx> for Ty<'tcx> { } } +pub struct CycleError<'a> { + span: Span, + cycle: RefMut<'a, [(Span, Query)]> +} + impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { - fn report_cycle(self, span: Span, cycle: &[(Span, Query)]) { + pub fn report_cycle(self, CycleError { span, cycle }: CycleError) { assert!(!cycle.is_empty()); let mut err = struct_span_err!(self.sess, span, E0391, @@ -88,16 +92,18 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { err.emit(); } - fn cycle_check(self, span: Span, query: Query, compute: F) -> R + fn cycle_check(self, span: Span, query: Query, compute: F) + -> Result> where F: FnOnce() -> R { { let mut stack = self.maps.query_stack.borrow_mut(); if let Some((i, _)) = stack.iter().enumerate().rev() .find(|&(_, &(_, ref q))| *q == query) { - let cycle = &stack[i..]; - self.report_cycle(span, cycle); - return R::from_cycle_error(self.global_tcx()); + return Err(CycleError { + span: span, + cycle: RefMut::map(stack, |stack| &mut stack[i..]) + }); } stack.push((span, query)); } @@ -105,7 +111,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { let result = compute(); self.maps.query_stack.borrow_mut().pop(); - result + + Ok(result) } } @@ -140,7 +147,7 @@ macro_rules! define_maps { pub $name:ident: $node:ident($K:ty) -> $V:ty),*) => { pub struct Maps<$tcx> { providers: IndexVec>, - pub query_stack: RefCell>, + query_stack: RefCell>, $($(#[$attr])* pub $name: RefCell>>),* } @@ -182,7 +189,60 @@ macro_rules! define_maps { $(impl<$tcx> DepTrackingMapConfig for queries::$name<$tcx> { type Key = $K; type Value = $V; - fn to_dep_node(key: &$K) -> DepNode { DepNode::$node(*key) } + + #[allow(unused)] + fn to_dep_node(key: &$K) -> DepNode { + use dep_graph::DepNode::*; + + $node(*key) + } + } + impl<'a, $tcx, 'lcx> queries::$name<$tcx> { + fn try_get_with(tcx: TyCtxt<'a, $tcx, 'lcx>, + mut span: Span, + key: $K, + f: F) + -> Result> + where F: FnOnce(&$V) -> R + { + if let Some(result) = tcx.maps.$name.borrow().get(&key) { + return Ok(f(result)); + } + + // FIXME(eddyb) Get more valid Span's on queries. + if span == DUMMY_SP { + span = key.default_span(tcx); + } + + let _task = tcx.dep_graph.in_task(Self::to_dep_node(&key)); + + let result = tcx.cycle_check(span, Query::$name(key), || { + let provider = tcx.maps.providers[key.map_crate()].$name; + provider(tcx.global_tcx(), key) + })?; + + Ok(f(&tcx.maps.$name.borrow_mut().entry(key).or_insert(result))) + } + + pub fn try_get(tcx: TyCtxt<'a, $tcx, 'lcx>, span: Span, key: $K) + -> Result<$V, CycleError<'a>> { + Self::try_get_with(tcx, span, key, Clone::clone) + } + + $(#[$attr])* + pub fn get(tcx: TyCtxt<'a, $tcx, 'lcx>, span: Span, key: $K) -> $V { + Self::try_get(tcx, span, key).unwrap_or_else(|e| { + tcx.report_cycle(e); + Value::from_cycle_error(tcx.global_tcx()) + }) + } + + pub fn force(tcx: TyCtxt<'a, $tcx, 'lcx>, span: Span, key: $K) { + match Self::try_get_with(tcx, span, key, |_| ()) { + Ok(()) => {} + Err(e) => tcx.report_cycle(e) + } + } })* pub struct Providers<$tcx> { @@ -203,26 +263,6 @@ macro_rules! define_maps { Providers { $($name),* } } } - - impl<'a, $tcx, 'lcx> Maps<$tcx> { - $($(#[$attr])* - pub fn $name(&self, - tcx: TyCtxt<'a, $tcx, 'lcx>, - mut span: Span, - key: $K) -> $V { - self.$name.memoize(key, || { - // FIXME(eddyb) Get more valid Span's on queries. - if span == DUMMY_SP { - span = key.default_span(tcx); - } - - tcx.cycle_check(span, Query::$name(key), || { - let provider = self.providers[key.map_crate()].$name; - provider(tcx.global_tcx(), key) - }) - }) - })* - } } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 357d12bc4dd6c..5ab0c9e565519 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -75,6 +75,8 @@ pub use self::context::{Lift, TypeckTables}; pub use self::trait_def::{TraitDef, TraitFlags}; +pub use self::maps::queries; + pub mod adjustment; pub mod cast; pub mod error; @@ -1947,7 +1949,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn item_tables(self, def_id: DefId) -> &'gcx TypeckTables<'gcx> { - self.maps.typeck_tables(self, DUMMY_SP, def_id) + queries::typeck_tables::get(self, DUMMY_SP, def_id) } pub fn expr_span(self, id: NodeId) -> Span { @@ -2055,12 +2057,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn custom_coerce_unsized_kind(self, did: DefId) -> adjustment::CustomCoerceUnsized { - self.maps.custom_coerce_unsized_kind(self, DUMMY_SP, did) + queries::custom_coerce_unsized_kind::get(self, DUMMY_SP, did) } pub fn associated_item(self, def_id: DefId) -> AssociatedItem { if !def_id.is_local() { - return self.maps.associated_item(self, DUMMY_SP, def_id); + return queries::associated_item::get(self, DUMMY_SP, def_id); } self.maps.associated_item.memoize(def_id, || { @@ -2165,7 +2167,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn associated_item_def_ids(self, def_id: DefId) -> Rc> { if !def_id.is_local() { - return self.maps.associated_item_def_ids(self, DUMMY_SP, def_id); + return queries::associated_item_def_ids::get(self, DUMMY_SP, def_id); } self.maps.associated_item_def_ids.memoize(def_id, || { @@ -2200,7 +2202,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// Returns the trait-ref corresponding to a given impl, or None if it is /// an inherent impl. pub fn impl_trait_ref(self, id: DefId) -> Option> { - self.maps.impl_trait_ref(self, DUMMY_SP, id) + queries::impl_trait_ref::get(self, DUMMY_SP, id) } // Returns `ty::VariantDef` if `def` refers to a struct, @@ -2279,37 +2281,37 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // If the given item is in an external crate, looks up its type and adds it to // the type cache. Returns the type parameters and type. pub fn item_type(self, did: DefId) -> Ty<'gcx> { - self.maps.ty(self, DUMMY_SP, did) + queries::ty::get(self, DUMMY_SP, did) } /// Given the did of a trait, returns its canonical trait ref. pub fn lookup_trait_def(self, did: DefId) -> &'gcx TraitDef { - self.maps.trait_def(self, DUMMY_SP, did) + queries::trait_def::get(self, DUMMY_SP, did) } /// Given the did of an ADT, return a reference to its definition. pub fn lookup_adt_def(self, did: DefId) -> &'gcx AdtDef { - self.maps.adt_def(self, DUMMY_SP, did) + queries::adt_def::get(self, DUMMY_SP, did) } /// Given the did of an item, returns its generics. pub fn item_generics(self, did: DefId) -> &'gcx Generics { - self.maps.generics(self, DUMMY_SP, did) + queries::generics::get(self, DUMMY_SP, did) } /// Given the did of an item, returns its full set of predicates. pub fn item_predicates(self, did: DefId) -> GenericPredicates<'gcx> { - self.maps.predicates(self, DUMMY_SP, did) + queries::predicates::get(self, DUMMY_SP, did) } /// Given the did of a trait, returns its superpredicates. pub fn item_super_predicates(self, did: DefId) -> GenericPredicates<'gcx> { - self.maps.super_predicates(self, DUMMY_SP, did) + queries::super_predicates::get(self, DUMMY_SP, did) } /// Given the did of an item, returns its MIR, borrowed immutably. pub fn item_mir(self, did: DefId) -> Ref<'gcx, Mir<'gcx>> { - self.maps.mir(self, DUMMY_SP, did).borrow() + queries::mir::get(self, DUMMY_SP, did).borrow() } /// If `type_needs_drop` returns true, then `ty` is definitely @@ -2361,7 +2363,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn item_variances(self, item_id: DefId) -> Rc> { - self.maps.variances(self, DUMMY_SP, item_id) + queries::variances::get(self, DUMMY_SP, item_id) } pub fn trait_has_default_impl(self, trait_def_id: DefId) -> bool { @@ -2436,11 +2438,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn closure_kind(self, def_id: DefId) -> ty::ClosureKind { - self.maps.closure_kind(self, DUMMY_SP, def_id) + queries::closure_kind::get(self, DUMMY_SP, def_id) } pub fn closure_type(self, def_id: DefId) -> ty::PolyFnSig<'tcx> { - self.maps.closure_type(self, DUMMY_SP, def_id) + queries::closure_type::get(self, DUMMY_SP, def_id) } /// Given the def_id of an impl, return the def_id of the trait it implements. diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index fc7b50f11da96..1b19e79d489d6 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -47,7 +47,7 @@ macro_rules! provide { (<$lt:tt> $tcx:ident, $def_id:ident, $cdata:ident $($name:ident => $compute:block)*) => { pub fn provide<$lt>(providers: &mut Providers<$lt>) { $(fn $name<'a, $lt:$lt>($tcx: TyCtxt<'a, $lt, $lt>, $def_id: DefId) - -> as + -> as DepTrackingMapConfig>::Value { assert!(!$def_id.is_local()); diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index f5fd7a152a87e..e73700f04fa4e 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -264,7 +264,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { discr: variant.discr, evaluated_discr: match variant.discr { ty::VariantDiscr::Explicit(def_id) => { - tcx.maps.monomorphic_const_eval(tcx, DUMMY_SP, def_id).ok() + ty::queries::monomorphic_const_eval::get(tcx, DUMMY_SP, def_id).ok() } ty::VariantDiscr::Relative(_) => None }, diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 2d373ca7473e5..aae3947df1424 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -243,7 +243,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let is_object = self_ty.map_or(false, |ty| ty.sty == TRAIT_OBJECT_DUMMY_SELF); let default_needs_object_self = |p: &ty::TypeParameterDef| { if is_object && p.has_default { - if tcx.maps.ty(tcx, span, p.def_id).has_self_ty() { + if ty::queries::ty::get(tcx, span, p.def_id).has_self_ty() { // There is no suitable inference default for a type parameter // that references self, in an object type. return true; @@ -310,7 +310,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { tcx.types.err } else { // This is a default type parameter. - tcx.maps.ty(tcx, span, def.def_id).subst_spanned(tcx, substs, Some(span)) + ty::queries::ty::get(tcx, span, def.def_id) + .subst_spanned(tcx, substs, Some(span)) } } else { // We've already errored above about the mismatch. @@ -599,7 +600,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { -> Ty<'tcx> { let substs = self.ast_path_substs_for_ty(span, did, item_segment); - self.tcx().maps.ty(self.tcx(), span, did).subst(self.tcx(), substs) + ty::queries::ty::get(self.tcx(), span, did).subst(self.tcx(), substs) } /// Transform a PolyTraitRef into a PolyExistentialTraitRef by @@ -985,7 +986,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { assert_eq!(opt_self_ty, None); tcx.prohibit_type_params(&path.segments); - let ty = tcx.maps.ty(tcx, span, def_id); + let ty = ty::queries::ty::get(tcx, span, def_id); if let Some(free_substs) = self.get_free_substs() { ty.subst(tcx, free_substs) } else { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 2a95f5f5d0804..83adbdaf0307d 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -262,7 +262,7 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> { def_id: DefId) -> ty::GenericPredicates<'tcx> { - self.tcx.maps.type_param_predicates(self.tcx, span, (self.item_def_id, def_id)) + ty::queries::type_param_predicates::get(self.tcx, span, (self.item_def_id, def_id)) } fn get_free_substs(&self) -> Option<&Substs<'tcx>> { @@ -532,7 +532,7 @@ fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &hir::Item) { hir::ItemTrait(..) => { tcx.item_generics(def_id); tcx.lookup_trait_def(def_id); - tcx.maps.super_predicates(tcx, it.span, def_id); + ty::queries::super_predicates::get(tcx, it.span, def_id); tcx.item_predicates(def_id); }, hir::ItemStruct(ref struct_def, _) | @@ -836,7 +836,7 @@ fn super_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Now require that immediate supertraits are converted, // which will, in turn, reach indirect supertraits. for bound in superbounds.iter().filter_map(|p| p.to_opt_poly_trait_ref()) { - tcx.maps.super_predicates(tcx, item.span, bound.def_id()); + ty::queries::super_predicates::get(tcx, item.span, bound.def_id()); } ty::GenericPredicates { diff --git a/src/test/compile-fail/cycle-trait-default-type-trait.rs b/src/test/compile-fail/cycle-trait-default-type-trait.rs index e6caeb34a8c8f..6825572b26c83 100644 --- a/src/test/compile-fail/cycle-trait-default-type-trait.rs +++ b/src/test/compile-fail/cycle-trait-default-type-trait.rs @@ -13,6 +13,7 @@ trait Foo> { //~^ ERROR unsupported cyclic reference + //~| ERROR unsupported cyclic reference } fn main() { }