about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/dep_graph/dep_tracking_map.rs6
-rw-r--r--src/librustc/ty/maps.rs100
-rw-r--r--src/librustc/ty/mod.rs32
-rw-r--r--src/librustc_metadata/cstore_impl.rs2
-rw-r--r--src/librustc_metadata/encoder.rs2
-rw-r--r--src/librustc_typeck/astconv.rs9
-rw-r--r--src/librustc_typeck/collect.rs6
-rw-r--r--src/test/compile-fail/cycle-trait-default-type-trait.rs1
8 files changed, 104 insertions, 54 deletions
diff --git a/src/librustc/dep_graph/dep_tracking_map.rs b/src/librustc/dep_graph/dep_tracking_map.rs
index 2ffc3951cc9..9f45e66f0d9 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<M: DepTrackingMapConfig> DepTrackingMap<M> {
         assert!(old_value.is_none());
     }
 
+    pub fn entry(&mut self, k: M::Key) -> Entry<M::Key, M::Value> {
+        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 ce4d1f5ec97..26c92e3e7ec 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<F, R>(self, span: Span, query: Query, compute: F) -> R
+    fn cycle_check<F, R>(self, span: Span, query: Query, compute: F)
+                         -> Result<R, CycleError<'a>>
         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<CrateNum, Providers<$tcx>>,
-            pub query_stack: RefCell<Vec<(Span, Query)>>,
+            query_stack: RefCell<Vec<(Span, Query)>>,
             $($(#[$attr])* pub $name: RefCell<DepTrackingMap<queries::$name<$tcx>>>),*
         }
 
@@ -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<DefId> { DepNode::$node(*key) }
+
+            #[allow(unused)]
+            fn to_dep_node(key: &$K) -> DepNode<DefId> {
+                use dep_graph::DepNode::*;
+
+                $node(*key)
+            }
+        }
+        impl<'a, $tcx, 'lcx> queries::$name<$tcx> {
+            fn try_get_with<F, R>(tcx: TyCtxt<'a, $tcx, 'lcx>,
+                                  mut span: Span,
+                                  key: $K,
+                                  f: F)
+                                  -> Result<R, CycleError<'a>>
+                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 357d12bc4dd..5ab0c9e5655 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<Vec<DefId>> {
         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<TraitRef<'gcx>> {
-        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<Vec<ty::Variance>> {
-        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 fc7b50f11da..1b19e79d489 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)
-                                    -> <ty::maps::queries::$name<$lt> as
+                                    -> <ty::queries::$name<$lt> as
                                         DepTrackingMapConfig>::Value {
                 assert!(!$def_id.is_local());
 
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index f5fd7a152a8..e73700f04fa 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 2d373ca7473..aae3947df14 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 2a95f5f5d08..83adbdaf030 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 e6caeb34a8c..6825572b26c 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<X = Box<Foo>> {
     //~^ ERROR unsupported cyclic reference
+    //~| ERROR unsupported cyclic reference
 }
 
 fn main() { }