]> git.lizzy.rs Git - rust.git/commitdiff
Refactor compiler to make use of dep-tracking-maps. Also, in cases where
authorNiko Matsakis <niko@alum.mit.edu>
Tue, 22 Dec 2015 21:39:33 +0000 (16:39 -0500)
committerNiko Matsakis <niko@alum.mit.edu>
Wed, 6 Jan 2016 02:05:51 +0000 (21:05 -0500)
we were using interior mutability (RefCells, TyIvar), add some reads/writes.

src/librustc/dep_graph/dep_tracking_map.rs
src/librustc/middle/ty/contents.rs
src/librustc/middle/ty/context.rs
src/librustc/middle/ty/ivar.rs
src/librustc/middle/ty/maps.rs [new file with mode: 0644]
src/librustc/middle/ty/mod.rs
src/librustc/middle/ty/trait_def.rs [new file with mode: 0644]
src/librustc/util/common.rs
src/librustc_metadata/decoder.rs
src/librustc_typeck/collect.rs

index 4f1063eae5029ee3a9570a4802ce564887d14912..501c1aff320635bc87c8573c9ffa3d216a4dd78a 100644 (file)
@@ -13,6 +13,7 @@
 use std::ops::Index;
 use std::hash::Hash;
 use std::marker::PhantomData;
+use util::common::MemoizationMap;
 
 use super::{DepNode, DepGraph};
 
@@ -70,6 +71,61 @@ pub fn contains_key(&self, k: &M::Key) -> bool {
     }
 }
 
+impl<M: DepTrackingMapId> MemoizationMap for RefCell<DepTrackingMap<M>> {
+    type Key = M::Key;
+    type Value = M::Value;
+
+    /// Memoizes an entry in the dep-tracking-map. If the entry is not
+    /// already present, then `op` will be executed to compute its value.
+    /// The resulting dependency graph looks like this:
+    ///
+    ///     [op] -> Map(key) -> CurrentTask
+    ///
+    /// Here, `[op]` represents whatever nodes `op` reads in the
+    /// course of execution; `Map(key)` represents the node for this
+    /// map; and `CurrentTask` represents the current task when
+    /// `memoize` is invoked.
+    ///
+    /// **Important:* when `op` is invoked, the current task will be
+    /// switched to `Map(key)`. Therefore, if `op` makes use of any
+    /// HIR nodes or shared state accessed through its closure
+    /// environment, it must explicitly read that state. As an
+    /// example, see `type_scheme_of_item` in `collect`, which looks
+    /// something like this:
+    ///
+    /// ```
+    /// fn type_scheme_of_item(..., item: &hir::Item) -> ty::TypeScheme<'tcx> {
+    ///     let item_def_id = ccx.tcx.map.local_def_id(it.id);
+    ///     ccx.tcx.tcache.memoized(item_def_id, || {
+    ///         ccx.tcx.dep_graph.read(DepNode::Hir(item_def_id)); // (*)
+    ///         compute_type_scheme_of_item(ccx, item)
+    ///     });
+    /// }
+    /// ```
+    ///
+    /// The key is the line marked `(*)`: the closure implicitly
+    /// accesses the body of the item `item`, so we register a read
+    /// from `Hir(item_def_id)`.
+    fn memoize<OP>(&self, key: M::Key, op: OP) -> M::Value
+        where OP: FnOnce() -> M::Value
+    {
+        let graph;
+        {
+            let this = self.borrow();
+            if let Some(result) = this.map.get(&key) {
+                this.read(&key);
+                return result.clone();
+            }
+            graph = this.graph.clone();
+        }
+
+        let _task = graph.in_task(M::to_dep_node(&key));
+        let result = op();
+        self.borrow_mut().map.insert(key, result.clone());
+        result
+    }
+}
+
 impl<'k, M: DepTrackingMapId> Index<&'k M::Key> for DepTrackingMap<M> {
     type Output = M::Value;
 
index afe88f70d945055a4ed325a317c18bc919489345..619201a4a9feb016742b05116520c29ca9974f7d 100644 (file)
@@ -10,7 +10,7 @@
 
 use middle::def_id::{DefId};
 use middle::ty::{self, Ty};
-use util::common::{memoized};
+use util::common::MemoizationMap;
 use util::nodemap::FnvHashMap;
 
 use std::fmt;
@@ -141,9 +141,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 
 impl<'tcx> ty::TyS<'tcx> {
     pub fn type_contents(&'tcx self, cx: &ty::ctxt<'tcx>) -> TypeContents {
-        return memoized(&cx.tc_cache, self, |ty| {
-            tc_ty(cx, ty, &mut FnvHashMap())
-        });
+        return cx.tc_cache.memoize(self, || tc_ty(cx, self, &mut FnvHashMap()));
 
         fn tc_ty<'tcx>(cx: &ty::ctxt<'tcx>,
                        ty: Ty<'tcx>,
index e700abf9db197b262da88fc37d1f18e5c619b2b4..8f313120c9de65dd4d2148f1b579eae169cd6c92 100644 (file)
 use middle::ty::{self, TraitRef, Ty, TypeAndMut};
 use middle::ty::{TyS, TypeVariants};
 use middle::ty::{AdtDef, ClosureSubsts, ExistentialBounds, Region};
-use middle::ty::{FreevarMap, GenericPredicates};
+use middle::ty::{FreevarMap};
 use middle::ty::{BareFnTy, InferTy, ParamTy, ProjectionTy, TraitTy};
 use middle::ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid};
 use middle::ty::TypeVariants::*;
+use middle::ty::maps;
+use util::common::MemoizationMap;
 use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet};
 use util::nodemap::FnvHashMap;
 
@@ -248,21 +250,23 @@ pub struct ctxt<'tcx> {
     pub tables: RefCell<Tables<'tcx>>,
 
     /// Maps from a trait item to the trait item "descriptor"
-    pub impl_or_trait_items: RefCell<DefIdMap<ty::ImplOrTraitItem<'tcx>>>,
+    pub impl_or_trait_items: RefCell<DepTrackingMap<maps::ImplOrTraitItems<'tcx>>>,
 
     /// Maps from a trait def-id to a list of the def-ids of its trait items
-    pub trait_item_def_ids: RefCell<DefIdMap<Rc<Vec<ty::ImplOrTraitItemId>>>>,
+    pub trait_item_def_ids: RefCell<DepTrackingMap<maps::TraitItemDefIds<'tcx>>>,
 
-    /// A cache for the trait_items() routine
-    pub trait_items_cache: RefCell<DefIdMap<Rc<Vec<ty::ImplOrTraitItem<'tcx>>>>>,
+    /// A cache for the trait_items() routine; note that the routine
+    /// itself pushes the `TraitItems` dependency node. This cache is
+    /// "encapsulated" and thus does not need to be itself tracked.
+    trait_items_cache: RefCell<DefIdMap<Rc<Vec<ty::ImplOrTraitItem<'tcx>>>>>,
 
-    pub impl_trait_refs: RefCell<DefIdMap<Option<TraitRef<'tcx>>>>,
-    pub trait_defs: RefCell<DefIdMap<&'tcx ty::TraitDef<'tcx>>>,
-    pub adt_defs: RefCell<DefIdMap<ty::AdtDefMaster<'tcx>>>,
+    pub impl_trait_refs: RefCell<DepTrackingMap<maps::ImplTraitRefs<'tcx>>>,
+    pub trait_defs: RefCell<DepTrackingMap<maps::TraitDefs<'tcx>>>,
+    pub adt_defs: RefCell<DepTrackingMap<maps::AdtDefs<'tcx>>>,
 
     /// Maps from the def-id of an item (trait/struct/enum/fn) to its
     /// associated predicates.
-    pub predicates: RefCell<DefIdMap<GenericPredicates<'tcx>>>,
+    pub predicates: RefCell<DepTrackingMap<maps::Predicates<'tcx>>>,
 
     /// Maps from the def-id of a trait to the list of
     /// super-predicates. This is a subset of the full list of
@@ -270,21 +274,40 @@ pub struct ctxt<'tcx> {
     /// evaluate them even during type conversion, often before the
     /// full predicates are available (note that supertraits have
     /// additional acyclicity requirements).
-    pub super_predicates: RefCell<DefIdMap<GenericPredicates<'tcx>>>,
+    pub super_predicates: RefCell<DepTrackingMap<maps::Predicates<'tcx>>>,
 
     pub map: ast_map::Map<'tcx>,
+
+    // Records the free variables refrenced by every closure
+    // expression. Do not track deps for this, just recompute it from
+    // scratch every time.
     pub freevars: RefCell<FreevarMap>,
-    pub tcache: RefCell<DefIdMap<ty::TypeScheme<'tcx>>>,
+
+    // Records the type of every item.
+    pub tcache: RefCell<DepTrackingMap<maps::Tcache<'tcx>>>,
+
+    // Internal cache for metadata decoding. No need to track deps on this.
     pub rcache: RefCell<FnvHashMap<ty::CReaderCacheKey, Ty<'tcx>>>,
+
+    // Cache for the type-contents routine. FIXME -- track deps?
     pub tc_cache: RefCell<FnvHashMap<Ty<'tcx>, ty::contents::TypeContents>>,
+
+    // Cache for various types within a method body and so forth.
+    //
+    // FIXME this should be made local to typeck, but it is currently used by one lint
     pub ast_ty_to_ty_cache: RefCell<NodeMap<Ty<'tcx>>>,
+
+    // FIXME no dep tracking, but we should be able to remove this
     pub ty_param_defs: RefCell<NodeMap<ty::TypeParameterDef<'tcx>>>,
+
+    // FIXME dep tracking -- should be harmless enough
     pub normalized_cache: RefCell<FnvHashMap<Ty<'tcx>, Ty<'tcx>>>,
+
     pub lang_items: middle::lang_items::LanguageItems,
 
     /// Maps from def-id of a type or region parameter to its
     /// (inferred) variance.
-    pub item_variance_map: RefCell<DefIdMap<Rc<ty::ItemVariances>>>,
+    pub item_variance_map: RefCell<DepTrackingMap<maps::ItemVariances<'tcx>>>,
 
     /// True if the variance has been computed yet; false otherwise.
     pub variance_computed: Cell<bool>,
@@ -292,13 +315,13 @@ pub struct ctxt<'tcx> {
     /// Maps a DefId of a type to a list of its inherent impls.
     /// Contains implementations of methods that are inherent to a type.
     /// Methods in these implementations don't need to be exported.
-    pub inherent_impls: RefCell<DefIdMap<Rc<Vec<DefId>>>>,
+    pub inherent_impls: RefCell<DepTrackingMap<maps::InherentImpls<'tcx>>>,
 
     /// Maps a DefId of an impl to a list of its items.
     /// Note that this contains all of the impls that we know about,
     /// including ones in other crates. It's not clear that this is the best
     /// way to do it.
-    pub impl_items: RefCell<DefIdMap<Vec<ty::ImplOrTraitItemId>>>,
+    pub impl_items: RefCell<DepTrackingMap<maps::ImplItems<'tcx>>>,
 
     /// Set of used unsafe nodes (functions or blocks). Unsafe nodes not
     /// present in this set can be warned about.
@@ -312,6 +335,7 @@ pub struct ctxt<'tcx> {
     /// The set of external nominal types whose implementations have been read.
     /// This is used for lazy resolution of methods.
     pub populated_external_types: RefCell<DefIdSet>,
+
     /// The set of external primitive types whose implementations have been read.
     /// FIXME(arielb1): why is this separate from populated_external_types?
     pub populated_external_primitive_impls: RefCell<DefIdSet>,
@@ -347,7 +371,9 @@ pub struct ctxt<'tcx> {
     pub fulfilled_predicates: RefCell<traits::FulfilledPredicates<'tcx>>,
 
     /// Caches the representation hints for struct definitions.
-    pub repr_hint_cache: RefCell<DefIdMap<Rc<Vec<attr::ReprAttr>>>>,
+    ///
+    /// This is encapsulated by the `ReprHints` task and hence is not tracked.
+    repr_hint_cache: RefCell<DefIdMap<Rc<Vec<attr::ReprAttr>>>>,
 
     /// Maps Expr NodeId's to their constant qualification.
     pub const_qualif_map: RefCell<NodeMap<middle::check_const::ConstQualif>>,
@@ -499,31 +525,31 @@ pub fn create_and_enter<F, R>(s: &'tcx Session,
             named_region_map: named_region_map,
             region_maps: region_maps,
             free_region_maps: RefCell::new(FnvHashMap()),
-            item_variance_map: RefCell::new(DefIdMap()),
+            item_variance_map: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
             variance_computed: Cell::new(false),
             sess: s,
             def_map: def_map,
             tables: RefCell::new(Tables::empty()),
-            impl_trait_refs: RefCell::new(DefIdMap()),
-            trait_defs: RefCell::new(DefIdMap()),
-            adt_defs: RefCell::new(DefIdMap()),
-            predicates: RefCell::new(DefIdMap()),
-            super_predicates: RefCell::new(DefIdMap()),
+            impl_trait_refs: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
+            trait_defs: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
+            adt_defs: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
+            predicates: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
+            super_predicates: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
             fulfilled_predicates: RefCell::new(traits::FulfilledPredicates::new()),
             map: map,
             freevars: RefCell::new(freevars),
-            tcache: RefCell::new(DefIdMap()),
+            tcache: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
             rcache: RefCell::new(FnvHashMap()),
             tc_cache: RefCell::new(FnvHashMap()),
             ast_ty_to_ty_cache: RefCell::new(NodeMap()),
-            impl_or_trait_items: RefCell::new(DefIdMap()),
-            trait_item_def_ids: RefCell::new(DefIdMap()),
+            impl_or_trait_items: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
+            trait_item_def_ids: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
             trait_items_cache: RefCell::new(DefIdMap()),
             ty_param_defs: RefCell::new(NodeMap()),
             normalized_cache: RefCell::new(FnvHashMap()),
             lang_items: lang_items,
-            inherent_impls: RefCell::new(DefIdMap()),
-            impl_items: RefCell::new(DefIdMap()),
+            inherent_impls: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
+            impl_items: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
             used_unsafe: RefCell::new(NodeSet()),
             used_mut_nodes: RefCell::new(NodeSet()),
             populated_external_types: RefCell::new(DefIdSet()),
@@ -1004,4 +1030,38 @@ pub fn mk_self_type(&self) -> Ty<'tcx> {
     pub fn mk_param_from_def(&self, def: &ty::TypeParameterDef) -> Ty<'tcx> {
         self.mk_param(def.space, def.index, def.name)
     }
+
+    pub fn trait_items(&self, trait_did: DefId) -> Rc<Vec<ty::ImplOrTraitItem<'tcx>>> {
+        // since this is cached, pushing a dep-node for the
+        // computation yields the correct dependencies.
+        let _task = self.dep_graph.in_task(DepNode::TraitItems(trait_did));
+
+        let mut trait_items = self.trait_items_cache.borrow_mut();
+        match trait_items.get(&trait_did).cloned() {
+            Some(trait_items) => trait_items,
+            None => {
+                let def_ids = self.trait_item_def_ids(trait_did);
+                let items: Rc<Vec<_>> =
+                    Rc::new(def_ids.iter()
+                                   .map(|d| self.impl_or_trait_item(d.def_id()))
+                                   .collect());
+                trait_items.insert(trait_did, items.clone());
+                items
+            }
+        }
+    }
+
+    /// Obtain the representation annotation for a struct definition.
+    pub fn lookup_repr_hints(&self, did: DefId) -> Rc<Vec<attr::ReprAttr>> {
+        let _task = self.dep_graph.in_task(DepNode::ReprHints(did));
+        self.repr_hint_cache.memoize(did, || {
+            Rc::new(if did.is_local() {
+                self.get_attrs(did).iter().flat_map(|meta| {
+                    attr::find_repr_attrs(self.sess.diagnostic(), meta).into_iter()
+                }).collect()
+            } else {
+                self.sess.cstore.repr_attrs(did)
+            })
+        })
+    }
 }
index 73d567d0acf40aeb846b8a236456e1147b0bb128..ffc12aa5aea198e37dde94deefcd2b52df5de614 100644 (file)
@@ -8,7 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use dep_graph::DepNode;
 use middle::ty::{Ty, TyS};
+use middle::ty::tls;
 
 use rustc_data_structures::ivar;
 
 ///     (B) no aliases to this value with a 'tcx longer than this
 ///         value's 'lt exist
 ///
+/// Dependency tracking: each ivar does not know what node in the
+/// dependency graph it is associated with, so when you get/fulfill
+/// you must supply a `DepNode` id. This should always be the same id!
+///
 /// NonZero is used rather than Unique because Unique isn't Copy.
 pub struct TyIVar<'tcx, 'lt: 'tcx>(ivar::Ivar<NonZero<*const TyS<'static>>>,
                                    PhantomData<fn(TyS<'lt>)->TyS<'tcx>>);
@@ -40,19 +46,28 @@ pub fn new() -> Self {
     }
 
     #[inline]
-    pub fn get(&self) -> Option<Ty<'tcx>> {
+    pub fn get(&self, dep_node: DepNode) -> Option<Ty<'tcx>> {
+        tls::with(|tcx| tcx.dep_graph.read(dep_node));
+        self.untracked_get()
+    }
+
+    #[inline]
+    fn untracked_get(&self) -> Option<Ty<'tcx>> {
         match self.0.get() {
             None => None,
             // valid because of invariant (A)
             Some(v) => Some(unsafe { &*(*v as *const TyS<'tcx>) })
         }
     }
+
     #[inline]
-    pub fn unwrap(&self) -> Ty<'tcx> {
-        self.get().unwrap()
+    pub fn unwrap(&self, dep_node: DepNode) -> Ty<'tcx> {
+        self.get(dep_node).unwrap()
     }
 
-    pub fn fulfill(&self, value: Ty<'lt>) {
+    pub fn fulfill(&self, dep_node: DepNode, value: Ty<'lt>) {
+        tls::with(|tcx| tcx.dep_graph.write(dep_node));
+
         // Invariant (A) is fulfilled, because by (B), every alias
         // of this has a 'tcx longer than 'lt.
         let value: *const TyS<'lt> = value;
@@ -64,7 +79,7 @@ pub fn fulfill(&self, value: Ty<'lt>) {
 
 impl<'tcx, 'lt> fmt::Debug for TyIVar<'tcx, 'lt> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self.get() {
+        match self.untracked_get() {
             Some(val) => write!(f, "TyIVar({:?})", val),
             None => f.write_str("TyIVar(<unfulfilled>)")
         }
diff --git a/src/librustc/middle/ty/maps.rs b/src/librustc/middle/ty/maps.rs
new file mode 100644 (file)
index 0000000..e1fea5b
--- /dev/null
@@ -0,0 +1,41 @@
+// 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 <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.
+
+use dep_graph::{DepNode, DepTrackingMapId};
+use middle::def_id::DefId;
+use middle::ty;
+use std::marker::PhantomData;
+use std::rc::Rc;
+
+macro_rules! dep_map_ty {
+    ($ty_name:ident : $node_name:ident ($key:ty) -> $value:ty) => {
+        pub struct $ty_name<'tcx> {
+            data: PhantomData<&'tcx ()>
+        }
+
+        impl<'tcx> DepTrackingMapId for $ty_name<'tcx> {
+            type Key = $key;
+            type Value = $value;
+            fn to_dep_node(key: &$key) -> DepNode { DepNode::$node_name(*key) }
+        }
+    }
+}
+
+dep_map_ty! { ImplOrTraitItems: ImplOrTraitItems(DefId) -> ty::ImplOrTraitItem<'tcx> }
+dep_map_ty! { Tcache: ItemSignature(DefId) -> ty::TypeScheme<'tcx> }
+dep_map_ty! { Predicates: ItemSignature(DefId) -> ty::GenericPredicates<'tcx> }
+dep_map_ty! { SuperPredicates: ItemSignature(DefId) -> ty::GenericPredicates<'tcx> }
+dep_map_ty! { TraitItemDefIds: TraitItemDefIds(DefId) -> Rc<Vec<ty::ImplOrTraitItemId>> }
+dep_map_ty! { ImplTraitRefs: ItemSignature(DefId) -> Option<ty::TraitRef<'tcx>> }
+dep_map_ty! { TraitDefs: ItemSignature(DefId) -> &'tcx ty::TraitDef<'tcx> }
+dep_map_ty! { AdtDefs: ItemSignature(DefId) -> ty::AdtDefMaster<'tcx> }
+dep_map_ty! { ItemVariances: ItemSignature(DefId) -> Rc<ty::ItemVariances> }
+dep_map_ty! { InherentImpls: InherentImpls(DefId) -> Rc<Vec<DefId>> }
+dep_map_ty! { ImplItems: ImplItems(DefId) -> Vec<ty::ImplOrTraitItemId> }
index f9d18e9929709b972039844af18b41602e38302e..10682655e63b878e066c58cf11f5df1c1190e96a 100644 (file)
@@ -18,6 +18,7 @@
 pub use self::IntVarValue::*;
 pub use self::LvaluePreference::*;
 
+use dep_graph::{self, DepNode};
 use front::map as ast_map;
 use front::map::LinkedPath;
 use middle;
 use middle::ty;
 use middle::ty::fold::TypeFolder;
 use middle::ty::walk::TypeWalker;
-use util::common::memoized;
-use util::nodemap::{NodeMap, NodeSet, DefIdMap};
+use util::common::MemoizationMap;
+use util::nodemap::{NodeMap, NodeSet};
 use util::nodemap::FnvHashMap;
 
 use serialize::{Encodable, Encoder, Decodable, Decoder};
 use std::borrow::{Borrow, Cow};
-use std::cell::{Cell, RefCell};
+use std::cell::Cell;
 use std::hash::{Hash, Hasher};
 use std::iter;
 use std::rc::Rc;
 pub use self::context::{ctxt, tls};
 pub use self::context::{CtxtArenas, Lift, Tables};
 
+pub use self::trait_def::{TraitDef, TraitFlags};
+
 pub mod adjustment;
 pub mod cast;
 pub mod error;
 pub mod fast_reject;
 pub mod fold;
 pub mod _match;
+pub mod maps;
 pub mod outlives;
 pub mod relate;
+pub mod trait_def;
 pub mod walk;
 pub mod wf;
 pub mod util;
@@ -1318,161 +1323,6 @@ pub struct TypeScheme<'tcx> {
     pub ty: Ty<'tcx>,
 }
 
-bitflags! {
-    flags TraitFlags: u32 {
-        const NO_TRAIT_FLAGS        = 0,
-        const HAS_DEFAULT_IMPL      = 1 << 0,
-        const IS_OBJECT_SAFE        = 1 << 1,
-        const OBJECT_SAFETY_VALID   = 1 << 2,
-        const IMPLS_VALID           = 1 << 3,
-    }
-}
-
-/// As `TypeScheme` but for a trait ref.
-pub struct TraitDef<'tcx> {
-    pub unsafety: hir::Unsafety,
-
-    /// If `true`, then this trait had the `#[rustc_paren_sugar]`
-    /// attribute, indicating that it should be used with `Foo()`
-    /// sugar. This is a temporary thing -- eventually any trait wil
-    /// be usable with the sugar (or without it).
-    pub paren_sugar: bool,
-
-    /// Generic type definitions. Note that `Self` is listed in here
-    /// as having a single bound, the trait itself (e.g., in the trait
-    /// `Eq`, there is a single bound `Self : Eq`). This is so that
-    /// default methods get to assume that the `Self` parameters
-    /// implements the trait.
-    pub generics: Generics<'tcx>,
-
-    pub trait_ref: TraitRef<'tcx>,
-
-    /// A list of the associated types defined in this trait. Useful
-    /// for resolving `X::Foo` type markers.
-    pub associated_type_names: Vec<Name>,
-
-    // Impls of this trait. To allow for quicker lookup, the impls are indexed
-    // by a simplified version of their Self type: impls with a simplifiable
-    // Self are stored in nonblanket_impls keyed by it, while all other impls
-    // are stored in blanket_impls.
-
-    /// Impls of the trait.
-    pub nonblanket_impls: RefCell<
-        FnvHashMap<fast_reject::SimplifiedType, Vec<DefId>>
-    >,
-
-    /// Blanket impls associated with the trait.
-    pub blanket_impls: RefCell<Vec<DefId>>,
-
-    /// Various flags
-    pub flags: Cell<TraitFlags>
-}
-
-impl<'tcx> TraitDef<'tcx> {
-    // returns None if not yet calculated
-    pub fn object_safety(&self) -> Option<bool> {
-        if self.flags.get().intersects(TraitFlags::OBJECT_SAFETY_VALID) {
-            Some(self.flags.get().intersects(TraitFlags::IS_OBJECT_SAFE))
-        } else {
-            None
-        }
-    }
-
-    pub fn set_object_safety(&self, is_safe: bool) {
-        assert!(self.object_safety().map(|cs| cs == is_safe).unwrap_or(true));
-        self.flags.set(
-            self.flags.get() | if is_safe {
-                TraitFlags::OBJECT_SAFETY_VALID | TraitFlags::IS_OBJECT_SAFE
-            } else {
-                TraitFlags::OBJECT_SAFETY_VALID
-            }
-        );
-    }
-
-    /// Records a trait-to-implementation mapping.
-    pub fn record_impl(&self,
-                       tcx: &ctxt<'tcx>,
-                       impl_def_id: DefId,
-                       impl_trait_ref: TraitRef<'tcx>) {
-        debug!("TraitDef::record_impl for {:?}, from {:?}",
-               self, impl_trait_ref);
-
-        // We don't want to borrow_mut after we already populated all impls,
-        // so check if an impl is present with an immutable borrow first.
-        if let Some(sty) = fast_reject::simplify_type(tcx,
-                                                      impl_trait_ref.self_ty(), false) {
-            if let Some(is) = self.nonblanket_impls.borrow().get(&sty) {
-                if is.contains(&impl_def_id) {
-                    return // duplicate - skip
-                }
-            }
-
-            self.nonblanket_impls.borrow_mut().entry(sty).or_insert(vec![]).push(impl_def_id)
-        } else {
-            if self.blanket_impls.borrow().contains(&impl_def_id) {
-                return // duplicate - skip
-            }
-            self.blanket_impls.borrow_mut().push(impl_def_id)
-        }
-    }
-
-
-    pub fn for_each_impl<F: FnMut(DefId)>(&self, tcx: &ctxt<'tcx>, mut f: F)  {
-        tcx.populate_implementations_for_trait_if_necessary(self.trait_ref.def_id);
-
-        for &impl_def_id in self.blanket_impls.borrow().iter() {
-            f(impl_def_id);
-        }
-
-        for v in self.nonblanket_impls.borrow().values() {
-            for &impl_def_id in v {
-                f(impl_def_id);
-            }
-        }
-    }
-
-    /// Iterate over every impl that could possibly match the
-    /// self-type `self_ty`.
-    pub fn for_each_relevant_impl<F: FnMut(DefId)>(&self,
-                                                   tcx: &ctxt<'tcx>,
-                                                   self_ty: Ty<'tcx>,
-                                                   mut f: F)
-    {
-        tcx.populate_implementations_for_trait_if_necessary(self.trait_ref.def_id);
-
-        for &impl_def_id in self.blanket_impls.borrow().iter() {
-            f(impl_def_id);
-        }
-
-        // simplify_type(.., false) basically replaces type parameters and
-        // projections with infer-variables. This is, of course, done on
-        // the impl trait-ref when it is instantiated, but not on the
-        // predicate trait-ref which is passed here.
-        //
-        // for example, if we match `S: Copy` against an impl like
-        // `impl<T:Copy> Copy for Option<T>`, we replace the type variable
-        // in `Option<T>` with an infer variable, to `Option<_>` (this
-        // doesn't actually change fast_reject output), but we don't
-        // replace `S` with anything - this impl of course can't be
-        // selected, and as there are hundreds of similar impls,
-        // considering them would significantly harm performance.
-        if let Some(simp) = fast_reject::simplify_type(tcx, self_ty, true) {
-            if let Some(impls) = self.nonblanket_impls.borrow().get(&simp) {
-                for &impl_def_id in impls {
-                    f(impl_def_id);
-                }
-            }
-        } else {
-            for v in self.nonblanket_impls.borrow().values() {
-                for &impl_def_id in v {
-                    f(impl_def_id);
-                }
-            }
-        }
-    }
-
-}
-
 bitflags! {
     flags AdtFlags: u32 {
         const NO_ADT_FLAGS        = 0,
@@ -1514,6 +1364,8 @@ pub struct FieldDefData<'tcx, 'container: 'tcx> {
     pub vis: hir::Visibility,
     /// TyIVar is used here to allow for variance (see the doc at
     /// AdtDefData).
+    ///
+    /// Note: direct accesses to `ty` must also add dep edges.
     ty: ivar::TyIVar<'tcx, 'container>
 }
 
@@ -1804,11 +1656,11 @@ pub fn ty(&self, tcx: &ctxt<'tcx>, subst: &Substs<'tcx>) -> Ty<'tcx> {
     }
 
     pub fn unsubst_ty(&self) -> Ty<'tcx> {
-        self.ty.unwrap()
+        self.ty.unwrap(DepNode::FieldTy(self.did))
     }
 
     pub fn fulfill_ty(&self, ty: Ty<'container>) {
-        self.ty.fulfill(ty);
+        self.ty.fulfill(DepNode::FieldTy(self.did), ty);
     }
 }
 
@@ -1931,31 +1783,20 @@ pub fn from_mutbl(m: hir::Mutability) -> Self {
 /// into the map by the `typeck::collect` phase.  If the def-id is external,
 /// then we have to go consult the crate loading code (and cache the result for
 /// the future).
-fn lookup_locally_or_in_crate_store<V, F>(descr: &str,
+fn lookup_locally_or_in_crate_store<M, F>(descr: &str,
                                           def_id: DefId,
-                                          map: &RefCell<DefIdMap<V>>,
-                                          load_external: F) -> V where
-    V: Clone,
-    F: FnOnce() -> V,
+                                          map: &M,
+                                          load_external: F)
+                                          -> M::Value where
+    M: MemoizationMap<Key=DefId>,
+    F: FnOnce() -> M::Value,
 {
-    match map.borrow().get(&def_id).cloned() {
-        Some(v) => { return v; }
-        None => { }
-    }
-
-    if def_id.is_local() {
-        panic!("No def'n found for {:?} in tcx.{}", def_id, descr);
-    }
-    let v = load_external();
-
-    // Don't consider this a write from the current task, since we are
-    // loading from another crate. (Note that the current task will
-    // already have registered a read in the call to `get` above.)
-    dep_graph.with_ignore(|| {
-        map.borrow_mut().insert(def_id, v.clone());
-    });
-
-    v
+    map.memoize(def_id, || {
+        if def_id.is_local() {
+            panic!("No def'n found for {:?} in tcx.{}", def_id, descr);
+        }
+        load_external()
+    })
 }
 
 impl BorrowKind {
@@ -2231,22 +2072,6 @@ pub fn associated_consts(&self, id: DefId) -> Vec<Rc<AssociatedConst<'tcx>>> {
         }
     }
 
-    pub fn trait_items(&self, trait_did: DefId) -> Rc<Vec<ImplOrTraitItem<'tcx>>> {
-        let mut trait_items = self.trait_items_cache.borrow_mut();
-        match trait_items.get(&trait_did).cloned() {
-            Some(trait_items) => trait_items,
-            None => {
-                let def_ids = self.trait_item_def_ids(trait_did);
-                let items: Rc<Vec<ImplOrTraitItem>> =
-                    Rc::new(def_ids.iter()
-                                   .map(|d| self.impl_or_trait_item(d.def_id()))
-                                   .collect());
-                trait_items.insert(trait_did, items.clone());
-                items
-            }
-        }
-    }
-
     pub fn trait_impl_polarity(&self, id: DefId) -> Option<hir::ImplPolarity> {
         if let Some(id) = self.map.as_local_node_id(id) {
             match self.map.find(id) {
@@ -2264,7 +2089,7 @@ pub fn trait_impl_polarity(&self, id: DefId) -> Option<hir::ImplPolarity> {
     }
 
     pub fn custom_coerce_unsized_kind(&self, did: DefId) -> adjustment::CustomCoerceUnsized {
-        memoized(&self.custom_coerce_unsized_kinds, did, |did: DefId| {
+        self.custom_coerce_unsized_kinds.memoize(did, || {
             let (kind, src) = if did.krate != LOCAL_CRATE {
                 (self.sess.cstore.custom_coerce_unsized_kind(did), "external")
             } else {
@@ -2427,19 +2252,6 @@ pub fn lookup_simd(&self, did: DefId) -> bool {
             || self.lookup_repr_hints(did).contains(&attr::ReprSimd)
     }
 
-    /// Obtain the representation annotation for a struct definition.
-    pub fn lookup_repr_hints(&self, did: DefId) -> Rc<Vec<attr::ReprAttr>> {
-        memoized(&self.repr_hint_cache, did, |did: DefId| {
-            Rc::new(if did.is_local() {
-                self.get_attrs(did).iter().flat_map(|meta| {
-                    attr::find_repr_attrs(self.sess.diagnostic(), meta).into_iter()
-                }).collect()
-            } else {
-                self.sess.cstore.repr_attrs(did)
-            })
-        })
-    }
-
     pub fn item_variances(&self, item_id: DefId) -> Rc<ItemVariances> {
         lookup_locally_or_in_crate_store(
             "item_variance_map", item_id, &self.item_variance_map,
diff --git a/src/librustc/middle/ty/trait_def.rs b/src/librustc/middle/ty/trait_def.rs
new file mode 100644 (file)
index 0000000..db001ce
--- /dev/null
@@ -0,0 +1,226 @@
+// 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 <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.
+
+use dep_graph::DepNode;
+use middle::def_id::DefId;
+use middle::ty;
+use middle::ty::fast_reject;
+use middle::ty::Ty;
+use std::borrow::{Borrow};
+use std::cell::{Cell, Ref, RefCell};
+use syntax::ast::Name;
+use rustc_front::hir;
+use util::nodemap::FnvHashMap;
+
+/// As `TypeScheme` but for a trait ref.
+pub struct TraitDef<'tcx> {
+    pub unsafety: hir::Unsafety,
+
+    /// If `true`, then this trait had the `#[rustc_paren_sugar]`
+    /// attribute, indicating that it should be used with `Foo()`
+    /// sugar. This is a temporary thing -- eventually any trait wil
+    /// be usable with the sugar (or without it).
+    pub paren_sugar: bool,
+
+    /// Generic type definitions. Note that `Self` is listed in here
+    /// as having a single bound, the trait itself (e.g., in the trait
+    /// `Eq`, there is a single bound `Self : Eq`). This is so that
+    /// default methods get to assume that the `Self` parameters
+    /// implements the trait.
+    pub generics: ty::Generics<'tcx>,
+
+    pub trait_ref: ty::TraitRef<'tcx>,
+
+    /// A list of the associated types defined in this trait. Useful
+    /// for resolving `X::Foo` type markers.
+    pub associated_type_names: Vec<Name>,
+
+    // Impls of this trait. To allow for quicker lookup, the impls are indexed
+    // by a simplified version of their Self type: impls with a simplifiable
+    // Self are stored in nonblanket_impls keyed by it, while all other impls
+    // are stored in blanket_impls.
+    //
+    // These lists are tracked by `DepNode::TraitImpls`; we don't use
+    // a DepTrackingMap but instead have the `TraitDef` insert the
+    // required reads/writes.
+
+    /// Impls of the trait.
+    nonblanket_impls: RefCell<
+        FnvHashMap<fast_reject::SimplifiedType, Vec<DefId>>
+    >,
+
+    /// Blanket impls associated with the trait.
+    blanket_impls: RefCell<Vec<DefId>>,
+
+    /// Various flags
+    pub flags: Cell<TraitFlags>
+}
+
+impl<'tcx> TraitDef<'tcx> {
+    pub fn new(unsafety: hir::Unsafety,
+               paren_sugar: bool,
+               generics: ty::Generics<'tcx>,
+               trait_ref: ty::TraitRef<'tcx>,
+               associated_type_names: Vec<Name>)
+               -> TraitDef<'tcx> {
+        TraitDef {
+            paren_sugar: paren_sugar,
+            unsafety: unsafety,
+            generics: generics,
+            trait_ref: trait_ref,
+            associated_type_names: associated_type_names,
+            nonblanket_impls: RefCell::new(FnvHashMap()),
+            blanket_impls: RefCell::new(vec![]),
+            flags: Cell::new(ty::TraitFlags::NO_TRAIT_FLAGS)
+        }
+    }
+
+    pub fn def_id(&self) -> DefId {
+        self.trait_ref.def_id
+    }
+
+    // returns None if not yet calculated
+    pub fn object_safety(&self) -> Option<bool> {
+        if self.flags.get().intersects(TraitFlags::OBJECT_SAFETY_VALID) {
+            Some(self.flags.get().intersects(TraitFlags::IS_OBJECT_SAFE))
+        } else {
+            None
+        }
+    }
+
+    pub fn set_object_safety(&self, is_safe: bool) {
+        assert!(self.object_safety().map(|cs| cs == is_safe).unwrap_or(true));
+        self.flags.set(
+            self.flags.get() | if is_safe {
+                TraitFlags::OBJECT_SAFETY_VALID | TraitFlags::IS_OBJECT_SAFE
+            } else {
+                TraitFlags::OBJECT_SAFETY_VALID
+            }
+        );
+    }
+
+    fn write_trait_impls(&self, tcx: &ty::ctxt<'tcx>) {
+        tcx.dep_graph.write(DepNode::TraitImpls(self.trait_ref.def_id));
+    }
+
+    fn read_trait_impls(&self, tcx: &ty::ctxt<'tcx>) {
+        tcx.dep_graph.read(DepNode::TraitImpls(self.trait_ref.def_id));
+    }
+
+    /// Records a trait-to-implementation mapping.
+    pub fn record_impl(&self,
+                       tcx: &ty::ctxt<'tcx>,
+                       impl_def_id: DefId,
+                       impl_trait_ref: ty::TraitRef<'tcx>) {
+        debug!("TraitDef::record_impl for {:?}, from {:?}",
+               self, impl_trait_ref);
+
+        // Record the write into the impl set, but only for local
+        // impls: external impls are handled differently.
+        if impl_def_id.is_local() {
+            self.write_trait_impls(tcx);
+        }
+
+        // We don't want to borrow_mut after we already populated all impls,
+        // so check if an impl is present with an immutable borrow first.
+        if let Some(sty) = fast_reject::simplify_type(tcx,
+                                                      impl_trait_ref.self_ty(), false) {
+            if let Some(is) = self.nonblanket_impls.borrow().get(&sty) {
+                if is.contains(&impl_def_id) {
+                    return // duplicate - skip
+                }
+            }
+
+            self.nonblanket_impls.borrow_mut().entry(sty).or_insert(vec![]).push(impl_def_id)
+        } else {
+            if self.blanket_impls.borrow().contains(&impl_def_id) {
+                return // duplicate - skip
+            }
+            self.blanket_impls.borrow_mut().push(impl_def_id)
+        }
+    }
+
+    pub fn for_each_impl<F: FnMut(DefId)>(&self, tcx: &ty::ctxt<'tcx>, mut f: F)  {
+        self.read_trait_impls(tcx);
+
+        tcx.populate_implementations_for_trait_if_necessary(self.trait_ref.def_id);
+
+        for &impl_def_id in self.blanket_impls.borrow().iter() {
+            f(impl_def_id);
+        }
+
+        for v in self.nonblanket_impls.borrow().values() {
+            for &impl_def_id in v {
+                f(impl_def_id);
+            }
+        }
+    }
+
+    /// Iterate over every impl that could possibly match the
+    /// self-type `self_ty`.
+    pub fn for_each_relevant_impl<F: FnMut(DefId)>(&self,
+                                                   tcx: &ty::ctxt<'tcx>,
+                                                   self_ty: Ty<'tcx>,
+                                                   mut f: F)
+    {
+        self.read_trait_impls(tcx);
+
+        tcx.populate_implementations_for_trait_if_necessary(self.trait_ref.def_id);
+
+        for &impl_def_id in self.blanket_impls.borrow().iter() {
+            f(impl_def_id);
+        }
+
+        // simplify_type(.., false) basically replaces type parameters and
+        // projections with infer-variables. This is, of course, done on
+        // the impl trait-ref when it is instantiated, but not on the
+        // predicate trait-ref which is passed here.
+        //
+        // for example, if we match `S: Copy` against an impl like
+        // `impl<T:Copy> Copy for Option<T>`, we replace the type variable
+        // in `Option<T>` with an infer variable, to `Option<_>` (this
+        // doesn't actually change fast_reject output), but we don't
+        // replace `S` with anything - this impl of course can't be
+        // selected, and as there are hundreds of similar impls,
+        // considering them would significantly harm performance.
+        if let Some(simp) = fast_reject::simplify_type(tcx, self_ty, true) {
+            if let Some(impls) = self.nonblanket_impls.borrow().get(&simp) {
+                for &impl_def_id in impls {
+                    f(impl_def_id);
+                }
+            }
+        } else {
+            for v in self.nonblanket_impls.borrow().values() {
+                for &impl_def_id in v {
+                    f(impl_def_id);
+                }
+            }
+        }
+    }
+
+    pub fn borrow_impl_lists<'s>(&'s self, tcx: &ty::ctxt<'tcx>)
+                                 -> (Ref<'s, Vec<DefId>>,
+                                     Ref<'s, FnvHashMap<fast_reject::SimplifiedType, Vec<DefId>>>) {
+        self.read_trait_impls(tcx);
+        (self.blanket_impls.borrow(), self.nonblanket_impls.borrow())
+    }
+
+}
+
+bitflags! {
+    flags TraitFlags: u32 {
+        const NO_TRAIT_FLAGS        = 0,
+        const HAS_DEFAULT_IMPL      = 1 << 0,
+        const IS_OBJECT_SAFE        = 1 << 1,
+        const OBJECT_SAFETY_VALID   = 1 << 2,
+        const IMPLS_VALID           = 1 << 3,
+    }
+}
+
index b5d259d9ac999f1c84a3714947da28b1c4a8bc3e..2481cab78b4d6f15bdf37bf15d65c19a557cd38c 100644 (file)
@@ -201,46 +201,38 @@ pub fn block_query<P>(b: &hir::Block, p: P) -> bool where P: FnMut(&hir::Expr) -
     return v.flag;
 }
 
-/// Memoizes a one-argument closure using the given RefCell containing
-/// a type implementing MutableMap to serve as a cache.
-///
-/// In the future the signature of this function is expected to be:
-/// ```
-/// pub fn memoized<T: Clone, U: Clone, M: MutableMap<T, U>>(
-///    cache: &RefCell<M>,
-///    f: &|T| -> U
-/// ) -> impl |T| -> U {
-/// ```
-/// but currently it is not possible.
-///
-/// # Examples
-/// ```
-/// struct Context {
-///    cache: RefCell<HashMap<usize, usize>>
-/// }
-///
-/// fn factorial(ctxt: &Context, n: usize) -> usize {
-///     memoized(&ctxt.cache, n, |n| match n {
-///         0 | 1 => n,
-///         _ => factorial(ctxt, n - 2) + factorial(ctxt, n - 1)
-///     })
-/// }
-/// ```
-#[inline(always)]
-pub fn memoized<T, U, S, F>(cache: &RefCell<HashMap<T, U, S>>, arg: T, f: F) -> U
-    where T: Clone + Hash + Eq,
-          U: Clone,
-          S: HashState,
-          F: FnOnce(T) -> U,
+pub trait MemoizationMap {
+    type Key: Clone;
+    type Value: Clone;
+
+    /// If `key` is present in the map, return the valuee,
+    /// otherwise invoke `op` and store the value in the map.
+    ///
+    /// NB: if the receiver is a `DepTrackingMap`, special care is
+    /// needed in the `op` to ensure that the correct edges are
+    /// added into the dep graph. See the `DepTrackingMap` impl for
+    /// more details!
+    fn memoize<OP>(&self, key: Self::Key, op: OP) -> Self::Value
+        where OP: FnOnce() -> Self::Value;
+}
+
+impl<K, V, S> MemoizationMap for RefCell<HashMap<K,V,S>>
+    where K: Hash+Eq+Clone, V: Clone, S: HashState
 {
-    let key = arg.clone();
-    let result = cache.borrow().get(&key).cloned();
-    match result {
-        Some(result) => result,
-        None => {
-            let result = f(arg);
-            cache.borrow_mut().insert(key, result.clone());
-            result
+    type Key = K;
+    type Value = V;
+
+    fn memoize<OP>(&self, key: K, op: OP) -> V
+        where OP: FnOnce() -> V
+    {
+        let result = self.borrow().get(&key).cloned();
+        match result {
+            Some(result) => result,
+            None => {
+                let result = op();
+                self.borrow_mut().insert(key, result.clone());
+                result
+            }
         }
     }
 }
index 54cccf087ebb61a0ec0c417317b784b2d9b25bf9..0b48cad36ba8fefddfc9e0f0b1dcb8423a58eb97 100644 (file)
@@ -38,7 +38,7 @@
 use rustc::mir;
 use rustc::mir::visit::MutVisitor;
 
-use std::cell::{Cell, RefCell};
+use std::cell::Cell;
 use std::io::prelude::*;
 use std::io;
 use std::rc::Rc;
@@ -353,16 +353,11 @@ pub fn get_trait_def<'tcx>(cdata: Cmd,
     let associated_type_names = parse_associated_type_names(item_doc);
     let paren_sugar = parse_paren_sugar(item_doc);
 
-    ty::TraitDef {
-        paren_sugar: paren_sugar,
-        unsafety: unsafety,
-        generics: generics,
-        trait_ref: item_trait_ref(item_doc, tcx, cdata),
-        associated_type_names: associated_type_names,
-        nonblanket_impls: RefCell::new(FnvHashMap()),
-        blanket_impls: RefCell::new(vec![]),
-        flags: Cell::new(ty::TraitFlags::NO_TRAIT_FLAGS)
-    }
+    ty::TraitDef::new(unsafety,
+                      paren_sugar,
+                      generics,
+                      item_trait_ref(item_doc, tcx, cdata),
+                      associated_type_names)
 }
 
 pub fn get_adt_def<'tcx>(intr: &IdentInterner,
index d161324f5644fec798bc0f26e4eddd495e102562..5a9b899175837c4259f546fce4b6eca6b7ee4b58 100644 (file)
 use rscope::*;
 use rustc::dep_graph::DepNode;
 use rustc::front::map as hir_map;
-use util::common::{ErrorReported, memoized};
+use util::common::{ErrorReported, MemoizationMap};
 use util::nodemap::{FnvHashMap, FnvHashSet};
 use write_ty_to_tcx;
 
-use std::cell::{Cell, RefCell};
+use std::cell::RefCell;
 use std::collections::HashSet;
 use std::rc::Rc;
 
@@ -1419,17 +1419,17 @@ fn type_scheme_of_def_id<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
 }
 
 fn type_scheme_of_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
-                                it: &hir::Item)
+                                item: &hir::Item)
                                 -> ty::TypeScheme<'tcx>
 {
-    // Computing the type scheme of an item is a discrete task:
-    let item_def_id = ccx.tcx.map.local_def_id(it.id);
-    let _task = ccx.tcx.dep_graph.in_task(DepNode::TypeScheme(item_def_id));
-    ccx.tcx.dep_graph.read(DepNode::Hir(item_def_id)); // we have access to `it`
-
-    memoized(&ccx.tcx.tcache,
-             ccx.tcx.map.local_def_id(it.id),
-             |_| compute_type_scheme_of_item(ccx, it))
+    let item_def_id = ccx.tcx.map.local_def_id(item.id);
+    ccx.tcx.tcache.memoize(item_def_id, || {
+        // NB. Since the `memoized` function enters a new task, and we
+        // are giving this task access to the item `item`, we must
+        // register a read.
+        ccx.tcx.dep_graph.read(DepNode::Hir(item_def_id));
+        compute_type_scheme_of_item(ccx, item)
+    })
 }
 
 fn compute_type_scheme_of_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
@@ -1547,14 +1547,14 @@ fn type_scheme_of_foreign_item<'a, 'tcx>(
     abi: abi::Abi)
     -> ty::TypeScheme<'tcx>
 {
-    // Computing the type scheme of a foreign item is a discrete task:
     let item_def_id = ccx.tcx.map.local_def_id(item.id);
-    let _task = ccx.tcx.dep_graph.in_task(DepNode::TypeScheme(item_def_id));
-    ccx.tcx.dep_graph.read(DepNode::Hir(item_def_id)); // we have access to `item`
-
-    memoized(&ccx.tcx.tcache,
-             ccx.tcx.map.local_def_id(item.id),
-             |_| compute_type_scheme_of_foreign_item(ccx, item, abi))
+    ccx.tcx.tcache.memoize(item_def_id, || {
+        // NB. Since the `memoized` function enters a new task, and we
+        // are giving this task access to the item `item`, we must
+        // register a read.
+        ccx.tcx.dep_graph.read(DepNode::Hir(item_def_id));
+        compute_type_scheme_of_foreign_item(ccx, item, abi)
+    })
 }
 
 fn compute_type_scheme_of_foreign_item<'a, 'tcx>(