about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2016-03-28 17:37:34 -0400
committerNiko Matsakis <niko@alum.mit.edu>2016-04-06 12:42:46 -0400
commita9b6205aff943d44820df53d63d14a06b319b9dd (patch)
tree7755216f4f44edf533195805697e806c02c68c1f
parentb1e68b9e2d75e66bc866a194b744ddf8502ca129 (diff)
downloadrust-a9b6205aff943d44820df53d63d14a06b319b9dd.tar.gz
rust-a9b6205aff943d44820df53d63d14a06b319b9dd.zip
break dep-graph into modules, parameterize DepNode
it is useful later to customize how change the type we use for reference
items away from DefId
-rw-r--r--src/librustc/dep_graph/dep_node.rs207
-rw-r--r--src/librustc/dep_graph/dep_tracking_map.rs3
-rw-r--r--src/librustc/dep_graph/edges.rs28
-rw-r--r--src/librustc/dep_graph/graph.rs71
-rw-r--r--src/librustc/dep_graph/mod.rs206
-rw-r--r--src/librustc/dep_graph/query.rs40
-rw-r--r--src/librustc/dep_graph/raii.rs6
-rw-r--r--src/librustc/dep_graph/thread.rs15
-rw-r--r--src/librustc/dep_graph/visit.rs56
-rw-r--r--src/librustc/hir/map/mod.rs2
-rw-r--r--src/librustc/ty/ivar.rs7
-rw-r--r--src/librustc/ty/maps.rs2
-rw-r--r--src/librustc/ty/mod.rs6
-rw-r--r--src/librustc_mir/transform/type_check.rs3
-rw-r--r--src/librustc_trans/context.rs2
15 files changed, 411 insertions, 243 deletions
diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
new file mode 100644
index 00000000000..446313f7037
--- /dev/null
+++ b/src/librustc/dep_graph/dep_node.rs
@@ -0,0 +1,207 @@
+// Copyright 2014 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 std::fmt::Debug;
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
+pub enum DepNode<D: Clone + Debug> {
+    // The `D` type is "how definitions are identified".
+    // During compilation, it is always `DefId`, but when serializing
+    // it is mapped to `DefPath`.
+
+    // Represents the `Krate` as a whole (the `hir::Krate` value) (as
+    // distinct from the krate module). This is basically a hash of
+    // the entire krate, so if you read from `Krate` (e.g., by calling
+    // `tcx.map.krate()`), we will have to assume that any change
+    // means that you need to be recompiled. This is because the
+    // `Krate` value gives you access to all other items. To avoid
+    // this fate, do not call `tcx.map.krate()`; instead, prefer
+    // wrappers like `tcx.visit_all_items_in_krate()`.  If there is no
+    // suitable wrapper, you can use `tcx.dep_graph.ignore()` to gain
+    // access to the krate, but you must remember to add suitable
+    // edges yourself for the individual items that you read.
+    Krate,
+
+    // Represents the HIR node with the given node-id
+    Hir(D),
+
+    // Represents different phases in the compiler.
+    CrateReader,
+    CollectLanguageItems,
+    CheckStaticRecursion,
+    ResolveLifetimes,
+    RegionResolveCrate,
+    CheckLoops,
+    PluginRegistrar,
+    StabilityIndex,
+    CollectItem(D),
+    Coherence,
+    EffectCheck,
+    Liveness,
+    Resolve,
+    EntryPoint,
+    CheckEntryFn,
+    CoherenceCheckImpl(D),
+    CoherenceOverlapCheck(D),
+    CoherenceOverlapCheckSpecial(D),
+    CoherenceOverlapInherentCheck(D),
+    CoherenceOrphanCheck(D),
+    Variance,
+    WfCheck(D),
+    TypeckItemType(D),
+    TypeckItemBody(D),
+    Dropck,
+    DropckImpl(D),
+    CheckConst(D),
+    Privacy,
+    IntrinsicCheck(D),
+    MatchCheck(D),
+    MirMapConstruction(D),
+    MirTypeck(D),
+    BorrowCheck(D),
+    RvalueCheck(D),
+    Reachability,
+    DeadCheck,
+    StabilityCheck,
+    LateLintCheck,
+    IntrinsicUseCheck,
+    TransCrate,
+    TransCrateItem(D),
+    TransInlinedItem(D),
+    TransWriteMetadata,
+
+    // Nodes representing bits of computed IR in the tcx. Each shared
+    // table in the tcx (or elsewhere) maps to one of these
+    // nodes. Often we map multiple tables to the same node if there
+    // is no point in distinguishing them (e.g., both the type and
+    // predicates for an item wind up in `ItemSignature`). Other
+    // times, such as `ImplItems` vs `TraitItemDefIds`, tables which
+    // might be mergable are kept distinct because the sets of def-ids
+    // to which they apply are disjoint, and hence we might as well
+    // have distinct labels for easier debugging.
+    ImplOrTraitItems(D),
+    ItemSignature(D),
+    FieldTy(D),
+    TraitItemDefIds(D),
+    InherentImpls(D),
+    ImplItems(D),
+
+    // The set of impls for a given trait. Ultimately, it would be
+    // nice to get more fine-grained here (e.g., to include a
+    // simplified type), but we can't do that until we restructure the
+    // HIR to distinguish the *header* of an impl from its body.  This
+    // is because changes to the header may change the self-type of
+    // the impl and hence would require us to be more conservative
+    // than changes in the impl body.
+    TraitImpls(D),
+
+    // Nodes representing caches. To properly handle a true cache, we
+    // don't use a DepTrackingMap, but rather we push a task node.
+    // Otherwise the write into the map would be incorrectly
+    // attributed to the first task that happened to fill the cache,
+    // which would yield an overly conservative dep-graph.
+    TraitItems(D),
+    ReprHints(D),
+    TraitSelect(D),
+}
+
+impl<D: Clone + Debug> DepNode<D> {
+    /// Used in testing
+    pub fn from_label_string(label: &str, data: D) -> Result<DepNode<D>, ()> {
+        macro_rules! check {
+            ($($name:ident,)*) => {
+                match label {
+                    $(stringify!($name) => Ok(DepNode::$name(data)),)*
+                    _ => Err(())
+                }
+            }
+        }
+
+        check! {
+            CollectItem,
+            BorrowCheck,
+            TransCrateItem,
+            TypeckItemType,
+            TypeckItemBody,
+            ImplOrTraitItems,
+            ItemSignature,
+            FieldTy,
+            TraitItemDefIds,
+            InherentImpls,
+            ImplItems,
+            TraitImpls,
+            ReprHints,
+        }
+    }
+
+    pub fn map_def<E, OP>(&self, mut op: OP) -> Option<DepNode<E>>
+        where OP: FnMut(&D) -> Option<E>, E: Clone + Debug
+    {
+        use self::DepNode::*;
+
+        match *self {
+            Krate => Some(Krate),
+            CrateReader => Some(CrateReader),
+            CollectLanguageItems => Some(CollectLanguageItems),
+            CheckStaticRecursion => Some(CheckStaticRecursion),
+            ResolveLifetimes => Some(ResolveLifetimes),
+            RegionResolveCrate => Some(RegionResolveCrate),
+            CheckLoops => Some(CheckLoops),
+            PluginRegistrar => Some(PluginRegistrar),
+            StabilityIndex => Some(StabilityIndex),
+            Coherence => Some(Coherence),
+            EffectCheck => Some(EffectCheck),
+            Liveness => Some(Liveness),
+            Resolve => Some(Resolve),
+            EntryPoint => Some(EntryPoint),
+            CheckEntryFn => Some(CheckEntryFn),
+            Variance => Some(Variance),
+            Dropck => Some(Dropck),
+            Privacy => Some(Privacy),
+            Reachability => Some(Reachability),
+            DeadCheck => Some(DeadCheck),
+            StabilityCheck => Some(StabilityCheck),
+            LateLintCheck => Some(LateLintCheck),
+            IntrinsicUseCheck => Some(IntrinsicUseCheck),
+            TransCrate => Some(TransCrate),
+            TransWriteMetadata => Some(TransWriteMetadata),
+            Hir(ref d) => op(d).map(Hir),
+            CollectItem(ref d) => op(d).map(CollectItem),
+            CoherenceCheckImpl(ref d) => op(d).map(CoherenceCheckImpl),
+            CoherenceOverlapCheck(ref d) => op(d).map(CoherenceOverlapCheck),
+            CoherenceOverlapCheckSpecial(ref d) => op(d).map(CoherenceOverlapCheckSpecial),
+            CoherenceOverlapInherentCheck(ref d) => op(d).map(CoherenceOverlapInherentCheck),
+            CoherenceOrphanCheck(ref d) => op(d).map(CoherenceOrphanCheck),
+            WfCheck(ref d) => op(d).map(WfCheck),
+            TypeckItemType(ref d) => op(d).map(TypeckItemType),
+            TypeckItemBody(ref d) => op(d).map(TypeckItemBody),
+            DropckImpl(ref d) => op(d).map(DropckImpl),
+            CheckConst(ref d) => op(d).map(CheckConst),
+            IntrinsicCheck(ref d) => op(d).map(IntrinsicCheck),
+            MatchCheck(ref d) => op(d).map(MatchCheck),
+            MirMapConstruction(ref d) => op(d).map(MirMapConstruction),
+            MirTypeck(ref d) => op(d).map(MirTypeck),
+            BorrowCheck(ref d) => op(d).map(BorrowCheck),
+            RvalueCheck(ref d) => op(d).map(RvalueCheck),
+            TransCrateItem(ref d) => op(d).map(TransCrateItem),
+            TransInlinedItem(ref d) => op(d).map(TransInlinedItem),
+            ImplOrTraitItems(ref d) => op(d).map(ImplOrTraitItems),
+            ItemSignature(ref d) => op(d).map(ItemSignature),
+            FieldTy(ref d) => op(d).map(FieldTy),
+            TraitItemDefIds(ref d) => op(d).map(TraitItemDefIds),
+            InherentImpls(ref d) => op(d).map(InherentImpls),
+            ImplItems(ref d) => op(d).map(ImplItems),
+            TraitImpls(ref d) => op(d).map(TraitImpls),
+            TraitItems(ref d) => op(d).map(TraitItems),
+            ReprHints(ref d) => op(d).map(ReprHints),
+            TraitSelect(ref d) => op(d).map(TraitSelect),
+        }
+    }
+}
diff --git a/src/librustc/dep_graph/dep_tracking_map.rs b/src/librustc/dep_graph/dep_tracking_map.rs
index c49e64f0f54..922d32a3067 100644
--- a/src/librustc/dep_graph/dep_tracking_map.rs
+++ b/src/librustc/dep_graph/dep_tracking_map.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use hir::def_id::DefId;
 use rustc_data_structures::fnv::FnvHashMap;
 use std::cell::RefCell;
 use std::ops::Index;
@@ -29,7 +30,7 @@ pub struct DepTrackingMap<M: DepTrackingMapConfig> {
 pub trait DepTrackingMapConfig {
     type Key: Eq + Hash + Clone;
     type Value: Clone;
-    fn to_dep_node(key: &Self::Key) -> DepNode;
+    fn to_dep_node(key: &Self::Key) -> DepNode<DefId>;
 }
 
 impl<M: DepTrackingMapConfig> DepTrackingMap<M> {
diff --git a/src/librustc/dep_graph/edges.rs b/src/librustc/dep_graph/edges.rs
index d3ced8aa518..10f3d21f2af 100644
--- a/src/librustc/dep_graph/edges.rs
+++ b/src/librustc/dep_graph/edges.rs
@@ -9,11 +9,13 @@
 // except according to those terms.
 
 use rustc_data_structures::fnv::{FnvHashMap, FnvHashSet};
+use std::fmt::Debug;
+use std::hash::Hash;
 use super::{DepGraphQuery, DepNode};
 
-pub struct DepGraphEdges {
-    nodes: Vec<DepNode>,
-    indices: FnvHashMap<DepNode, IdIndex>,
+pub struct DepGraphEdges<D: Clone + Debug + Eq + Hash> {
+    nodes: Vec<DepNode<D>>,
+    indices: FnvHashMap<DepNode<D>, IdIndex>,
     edges: FnvHashSet<(IdIndex, IdIndex)>,
     open_nodes: Vec<OpenNode>,
 }
@@ -40,8 +42,8 @@ enum OpenNode {
     Ignore,
 }
 
-impl DepGraphEdges {
-    pub fn new() -> DepGraphEdges {
+impl<D: Clone + Debug + Eq + Hash> DepGraphEdges<D> {
+    pub fn new() -> DepGraphEdges<D> {
         DepGraphEdges {
             nodes: vec![],
             indices: FnvHashMap(),
@@ -50,12 +52,12 @@ impl DepGraphEdges {
         }
     }
 
-    fn id(&self, index: IdIndex) -> DepNode {
-        self.nodes[index.index()]
+    fn id(&self, index: IdIndex) -> DepNode<D> {
+        self.nodes[index.index()].clone()
     }
 
     /// Creates a node for `id` in the graph.
-    fn make_node(&mut self, id: DepNode) -> IdIndex {
+    fn make_node(&mut self, id: DepNode<D>) -> IdIndex {
         if let Some(&i) = self.indices.get(&id) {
             return i;
         }
@@ -80,7 +82,7 @@ impl DepGraphEdges {
         assert_eq!(popped_node, OpenNode::Ignore);
     }
 
-    pub fn push_task(&mut self, key: DepNode) {
+    pub fn push_task(&mut self, key: DepNode<D>) {
         let top_node = self.current_node();
 
         let new_node = self.make_node(key);
@@ -93,7 +95,7 @@ impl DepGraphEdges {
         }
     }
 
-    pub fn pop_task(&mut self, key: DepNode) {
+    pub fn pop_task(&mut self, key: DepNode<D>) {
         let popped_node = self.open_nodes.pop().unwrap();
         assert_eq!(OpenNode::Node(self.indices[&key]), popped_node);
     }
@@ -101,7 +103,7 @@ impl DepGraphEdges {
     /// Indicates that the current task `C` reads `v` by adding an
     /// edge from `v` to `C`. If there is no current task, panics. If
     /// you want to suppress this edge, use `ignore`.
-    pub fn read(&mut self, v: DepNode) {
+    pub fn read(&mut self, v: DepNode<D>) {
         let source = self.make_node(v);
         self.add_edge_from_current_node(|current| (source, current))
     }
@@ -109,7 +111,7 @@ impl DepGraphEdges {
     /// Indicates that the current task `C` writes `v` by adding an
     /// edge from `C` to `v`. If there is no current task, panics. If
     /// you want to suppress this edge, use `ignore`.
-    pub fn write(&mut self, v: DepNode) {
+    pub fn write(&mut self, v: DepNode<D>) {
         let target = self.make_node(v);
         self.add_edge_from_current_node(|current| (current, target))
     }
@@ -153,7 +155,7 @@ impl DepGraphEdges {
         }
     }
 
-    pub fn query(&self) -> DepGraphQuery {
+    pub fn query(&self) -> DepGraphQuery<D> {
         let edges: Vec<_> = self.edges.iter()
                                       .map(|&(i, j)| (self.id(i), self.id(j)))
                                       .collect();
diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs
new file mode 100644
index 00000000000..741ad65c29f
--- /dev/null
+++ b/src/librustc/dep_graph/graph.rs
@@ -0,0 +1,71 @@
+// Copyright 2014 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 hir::def_id::DefId;
+use std::rc::Rc;
+
+use super::dep_node::DepNode;
+use super::query::DepGraphQuery;
+use super::raii;
+use super::thread::{DepGraphThreadData, DepMessage};
+
+#[derive(Clone)]
+pub struct DepGraph {
+    data: Rc<DepGraphThreadData>
+}
+
+impl DepGraph {
+    pub fn new(enabled: bool) -> DepGraph {
+        DepGraph {
+            data: Rc::new(DepGraphThreadData::new(enabled))
+        }
+    }
+
+    /// True if we are actually building a dep-graph. If this returns false,
+    /// then the other methods on this `DepGraph` will have no net effect.
+    #[inline]
+    pub fn enabled(&self) -> bool {
+        self.data.enabled()
+    }
+
+    pub fn query(&self) -> DepGraphQuery<DefId> {
+        self.data.query()
+    }
+
+    pub fn in_ignore<'graph>(&'graph self) -> raii::IgnoreTask<'graph> {
+        raii::IgnoreTask::new(&self.data)
+    }
+
+    pub fn in_task<'graph>(&'graph self, key: DepNode<DefId>) -> raii::DepTask<'graph> {
+        raii::DepTask::new(&self.data, key)
+    }
+
+    pub fn with_ignore<OP,R>(&self, op: OP) -> R
+        where OP: FnOnce() -> R
+    {
+        let _task = self.in_ignore();
+        op()
+    }
+
+    pub fn with_task<OP,R>(&self, key: DepNode<DefId>, op: OP) -> R
+        where OP: FnOnce() -> R
+    {
+        let _task = self.in_task(key);
+        op()
+    }
+
+    pub fn read(&self, v: DepNode<DefId>) {
+        self.data.enqueue(DepMessage::Read(v));
+    }
+
+    pub fn write(&self, v: DepNode<DefId>) {
+        self.data.enqueue(DepMessage::Write(v));
+    }
+}
diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs
index 55ec56a4bbe..49481dcb796 100644
--- a/src/librustc/dep_graph/mod.rs
+++ b/src/librustc/dep_graph/mod.rs
@@ -8,211 +8,17 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use self::thread::{DepGraphThreadData, DepMessage};
-use hir::def_id::DefId;
-use syntax::ast::NodeId;
-use ty::TyCtxt;
-use hir;
-use hir::intravisit::Visitor;
-use std::rc::Rc;
-
+mod dep_node;
 mod dep_tracking_map;
 mod edges;
+mod graph;
 mod query;
 mod raii;
 mod thread;
-
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
-pub enum DepNode {
-    // Represents the `Krate` as a whole (the `hir::Krate` value) (as
-    // distinct from the krate module). This is basically a hash of
-    // the entire krate, so if you read from `Krate` (e.g., by calling
-    // `tcx.map.krate()`), we will have to assume that any change
-    // means that you need to be recompiled. This is because the
-    // `Krate` value gives you access to all other items. To avoid
-    // this fate, do not call `tcx.map.krate()`; instead, prefer
-    // wrappers like `tcx.visit_all_items_in_krate()`.  If there is no
-    // suitable wrapper, you can use `tcx.dep_graph.ignore()` to gain
-    // access to the krate, but you must remember to add suitable
-    // edges yourself for the individual items that you read.
-    Krate,
-
-    // Represents the HIR node with the given node-id
-    Hir(DefId),
-
-    // Represents different phases in the compiler.
-    CrateReader,
-    CollectLanguageItems,
-    CheckStaticRecursion,
-    ResolveLifetimes,
-    RegionResolveCrate,
-    CheckLoops,
-    PluginRegistrar,
-    StabilityIndex,
-    CollectItem(DefId),
-    Coherence,
-    EffectCheck,
-    Liveness,
-    Resolve,
-    EntryPoint,
-    CheckEntryFn,
-    CoherenceCheckImpl(DefId),
-    CoherenceOverlapCheck(DefId),
-    CoherenceOverlapCheckSpecial(DefId),
-    CoherenceOverlapInherentCheck(DefId),
-    CoherenceOrphanCheck(DefId),
-    Variance,
-    WfCheck(DefId),
-    TypeckItemType(DefId),
-    TypeckItemBody(DefId),
-    Dropck,
-    DropckImpl(DefId),
-    CheckConst(DefId),
-    Privacy,
-    IntrinsicCheck(DefId),
-    MatchCheck(DefId),
-    MirMapConstruction(DefId),
-    MirTypeck(NodeId),
-    BorrowCheck(DefId),
-    RvalueCheck(DefId),
-    Reachability,
-    DeadCheck,
-    StabilityCheck,
-    LateLintCheck,
-    IntrinsicUseCheck,
-    TransCrate,
-    TransCrateItem(DefId),
-    TransInlinedItem(DefId),
-    TransWriteMetadata,
-
-    // Nodes representing bits of computed IR in the tcx. Each shared
-    // table in the tcx (or elsewhere) maps to one of these
-    // nodes. Often we map multiple tables to the same node if there
-    // is no point in distinguishing them (e.g., both the type and
-    // predicates for an item wind up in `ItemSignature`). Other
-    // times, such as `ImplItems` vs `TraitItemDefIds`, tables which
-    // might be mergable are kept distinct because the sets of def-ids
-    // to which they apply are disjoint, and hence we might as well
-    // have distinct labels for easier debugging.
-    ImplOrTraitItems(DefId),
-    ItemSignature(DefId),
-    FieldTy(DefId),
-    TraitItemDefIds(DefId),
-    InherentImpls(DefId),
-    ImplItems(DefId),
-
-    // The set of impls for a given trait. Ultimately, it would be
-    // nice to get more fine-grained here (e.g., to include a
-    // simplified type), but we can't do that until we restructure the
-    // HIR to distinguish the *header* of an impl from its body.  This
-    // is because changes to the header may change the self-type of
-    // the impl and hence would require us to be more conservative
-    // than changes in the impl body.
-    TraitImpls(DefId),
-
-    // Nodes representing caches. To properly handle a true cache, we
-    // don't use a DepTrackingMap, but rather we push a task node.
-    // Otherwise the write into the map would be incorrectly
-    // attributed to the first task that happened to fill the cache,
-    // which would yield an overly conservative dep-graph.
-    TraitItems(DefId),
-    ReprHints(DefId),
-    TraitSelect(DefId),
-}
-
-#[derive(Clone)]
-pub struct DepGraph {
-    data: Rc<DepGraphThreadData>
-}
-
-impl DepGraph {
-    pub fn new(enabled: bool) -> DepGraph {
-        DepGraph {
-            data: Rc::new(DepGraphThreadData::new(enabled))
-        }
-    }
-
-    /// True if we are actually building a dep-graph. If this returns false,
-    /// then the other methods on this `DepGraph` will have no net effect.
-    #[inline]
-    pub fn enabled(&self) -> bool {
-        self.data.enabled()
-    }
-
-    pub fn query(&self) -> DepGraphQuery {
-        self.data.query()
-    }
-
-    pub fn in_ignore<'graph>(&'graph self) -> raii::IgnoreTask<'graph> {
-        raii::IgnoreTask::new(&self.data)
-    }
-
-    pub fn in_task<'graph>(&'graph self, key: DepNode) -> raii::DepTask<'graph> {
-        raii::DepTask::new(&self.data, key)
-    }
-
-    pub fn with_ignore<OP,R>(&self, op: OP) -> R
-        where OP: FnOnce() -> R
-    {
-        let _task = self.in_ignore();
-        op()
-    }
-
-    pub fn with_task<OP,R>(&self, key: DepNode, op: OP) -> R
-        where OP: FnOnce() -> R
-    {
-        let _task = self.in_task(key);
-        op()
-    }
-
-    pub fn read(&self, v: DepNode) {
-        self.data.enqueue(DepMessage::Read(v));
-    }
-
-    pub fn write(&self, v: DepNode) {
-        self.data.enqueue(DepMessage::Write(v));
-    }
-}
+mod visit;
 
 pub use self::dep_tracking_map::{DepTrackingMap, DepTrackingMapConfig};
-
+pub use self::dep_node::DepNode;
+pub use self::graph::DepGraph;
 pub use self::query::DepGraphQuery;
-
-/// Visit all the items in the krate in some order. When visiting a
-/// particular item, first create a dep-node by calling `dep_node_fn`
-/// and push that onto the dep-graph stack of tasks, and also create a
-/// read edge from the corresponding AST node. This is used in
-/// compiler passes to automatically record the item that they are
-/// working on.
-pub fn visit_all_items_in_krate<'tcx,V,F>(tcx: &TyCtxt<'tcx>,
-                                          mut dep_node_fn: F,
-                                          visitor: &mut V)
-    where F: FnMut(DefId) -> DepNode, V: Visitor<'tcx>
-{
-    struct TrackingVisitor<'visit, 'tcx: 'visit, F: 'visit, V: 'visit> {
-        tcx: &'visit TyCtxt<'tcx>,
-        dep_node_fn: &'visit mut F,
-        visitor: &'visit mut V
-    }
-
-    impl<'visit, 'tcx, F, V> Visitor<'tcx> for TrackingVisitor<'visit, 'tcx, F, V>
-        where F: FnMut(DefId) -> DepNode, V: Visitor<'tcx>
-    {
-        fn visit_item(&mut self, i: &'tcx hir::Item) {
-            let item_def_id = self.tcx.map.local_def_id(i.id);
-            let task_id = (self.dep_node_fn)(item_def_id);
-            let _task = self.tcx.dep_graph.in_task(task_id);
-            debug!("Started task {:?}", task_id);
-            self.tcx.dep_graph.read(DepNode::Hir(item_def_id));
-            self.visitor.visit_item(i)
-        }
-    }
-
-    let krate = tcx.dep_graph.with_ignore(|| tcx.map.krate());
-    let mut tracking_visitor = TrackingVisitor {
-        tcx: tcx,
-        dep_node_fn: &mut dep_node_fn,
-        visitor: visitor
-    };
-    krate.visit_all_items(&mut tracking_visitor)
-}
+pub use self::visit::visit_all_items_in_krate;
diff --git a/src/librustc/dep_graph/query.rs b/src/librustc/dep_graph/query.rs
index 74a054acb4f..acc6660da6e 100644
--- a/src/librustc/dep_graph/query.rs
+++ b/src/librustc/dep_graph/query.rs
@@ -10,16 +10,20 @@
 
 use rustc_data_structures::fnv::FnvHashMap;
 use rustc_data_structures::graph::{Graph, NodeIndex};
+use std::fmt::Debug;
+use std::hash::Hash;
 
 use super::DepNode;
 
-pub struct DepGraphQuery {
-    pub graph: Graph<DepNode, ()>,
-    pub indices: FnvHashMap<DepNode, NodeIndex>,
+pub struct DepGraphQuery<D: Clone + Debug + Hash + Eq> {
+    pub graph: Graph<DepNode<D>, ()>,
+    pub indices: FnvHashMap<DepNode<D>, NodeIndex>,
 }
 
-impl DepGraphQuery {
-    pub fn new(nodes: &[DepNode], edges: &[(DepNode, DepNode)]) -> DepGraphQuery {
+impl<D: Clone + Debug + Hash + Eq> DepGraphQuery<D> {
+    pub fn new(nodes: &[DepNode<D>],
+               edges: &[(DepNode<D>, DepNode<D>)])
+               -> DepGraphQuery<D> {
         let mut graph = Graph::new();
         let mut indices = FnvHashMap();
         for node in nodes {
@@ -39,27 +43,43 @@ impl DepGraphQuery {
         }
     }
 
-    pub fn nodes(&self) -> Vec<DepNode> {
+    pub fn contains_node(&self, node: &DepNode<D>) -> bool {
+        self.indices.contains_key(&node)
+    }
+
+    pub fn nodes(&self) -> Vec<DepNode<D>> {
         self.graph.all_nodes()
                   .iter()
                   .map(|n| n.data.clone())
                   .collect()
     }
 
-    pub fn edges(&self) -> Vec<(DepNode,DepNode)> {
+    pub fn edges(&self) -> Vec<(DepNode<D>,DepNode<D>)> {
         self.graph.all_edges()
                   .iter()
                   .map(|edge| (edge.source(), edge.target()))
-                  .map(|(s, t)| (self.graph.node_data(s).clone(), self.graph.node_data(t).clone()))
+                  .map(|(s, t)| (self.graph.node_data(s).clone(),
+                                 self.graph.node_data(t).clone()))
                   .collect()
     }
 
     /// All nodes reachable from `node`. In other words, things that
     /// will have to be recomputed if `node` changes.
-    pub fn dependents(&self, node: DepNode) -> Vec<DepNode> {
+    pub fn transitive_dependents(&self, node: DepNode<D>) -> Vec<DepNode<D>> {
         if let Some(&index) = self.indices.get(&node) {
             self.graph.depth_traverse(index)
-                      .map(|dependent_node| self.graph.node_data(dependent_node).clone())
+                      .map(|s| self.graph.node_data(s).clone())
+                      .collect()
+        } else {
+            vec![]
+        }
+    }
+
+    /// Just the outgoing edges from `node`.
+    pub fn immediate_dependents(&self, node: DepNode<D>) -> Vec<DepNode<D>> {
+        if let Some(&index) = self.indices.get(&node) {
+            self.graph.successor_nodes(index)
+                      .map(|s| self.graph.node_data(s).clone())
                       .collect()
         } else {
             vec![]
diff --git a/src/librustc/dep_graph/raii.rs b/src/librustc/dep_graph/raii.rs
index dd7ff92f9c3..13151d169fc 100644
--- a/src/librustc/dep_graph/raii.rs
+++ b/src/librustc/dep_graph/raii.rs
@@ -8,16 +8,18 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use hir::def_id::DefId;
 use super::DepNode;
 use super::thread::{DepGraphThreadData, DepMessage};
 
 pub struct DepTask<'graph> {
     data: &'graph DepGraphThreadData,
-    key: DepNode,
+    key: DepNode<DefId>,
 }
 
 impl<'graph> DepTask<'graph> {
-    pub fn new(data: &'graph DepGraphThreadData, key: DepNode) -> DepTask<'graph> {
+    pub fn new(data: &'graph DepGraphThreadData, key: DepNode<DefId>)
+               -> DepTask<'graph> {
         data.enqueue(DepMessage::PushTask(key));
         DepTask { data: data, key: key }
     }
diff --git a/src/librustc/dep_graph/thread.rs b/src/librustc/dep_graph/thread.rs
index 1b1d3469bc5..5b0e4a909c8 100644
--- a/src/librustc/dep_graph/thread.rs
+++ b/src/librustc/dep_graph/thread.rs
@@ -18,6 +18,7 @@
 //! to accumulate more messages. This way we only ever have two vectors
 //! allocated (and both have a fairly large capacity).
 
+use hir::def_id::DefId;
 use rustc_data_structures::veccell::VecCell;
 use std::cell::Cell;
 use std::sync::mpsc::{self, Sender, Receiver};
@@ -28,10 +29,10 @@ use super::DepNode;
 use super::edges::DepGraphEdges;
 
 pub enum DepMessage {
-    Read(DepNode),
-    Write(DepNode),
-    PushTask(DepNode),
-    PopTask(DepNode),
+    Read(DepNode<DefId>),
+    Write(DepNode<DefId>),
+    PushTask(DepNode<DefId>),
+    PopTask(DepNode<DefId>),
     PushIgnore,
     PopIgnore,
     Query,
@@ -57,7 +58,7 @@ pub struct DepGraphThreadData {
     swap_out: Sender<Vec<DepMessage>>,
 
     // where to receive query results
-    query_in: Receiver<DepGraphQuery>,
+    query_in: Receiver<DepGraphQuery<DefId>>,
 }
 
 const INITIAL_CAPACITY: usize = 2048;
@@ -105,7 +106,7 @@ impl DepGraphThreadData {
         self.swap_out.send(old_messages).unwrap();
     }
 
-    pub fn query(&self) -> DepGraphQuery {
+    pub fn query(&self) -> DepGraphQuery<DefId> {
         assert!(self.enabled, "cannot query if dep graph construction not enabled");
         self.enqueue(DepMessage::Query);
         self.swap();
@@ -155,7 +156,7 @@ impl DepGraphThreadData {
 /// Definition of the depgraph thread.
 pub fn main(swap_in: Receiver<Vec<DepMessage>>,
             swap_out: Sender<Vec<DepMessage>>,
-            query_out: Sender<DepGraphQuery>) {
+            query_out: Sender<DepGraphQuery<DefId>>) {
     let mut edges = DepGraphEdges::new();
 
     // the compiler thread always expects a fresh buffer to be
diff --git a/src/librustc/dep_graph/visit.rs b/src/librustc/dep_graph/visit.rs
new file mode 100644
index 00000000000..8ce177efe92
--- /dev/null
+++ b/src/librustc/dep_graph/visit.rs
@@ -0,0 +1,56 @@
+// Copyright 2014 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 hir::def_id::DefId;
+use ty::TyCtxt;
+use rustc_front::hir;
+use rustc_front::intravisit::Visitor;
+
+use super::dep_node::DepNode;
+
+
+/// Visit all the items in the krate in some order. When visiting a
+/// particular item, first create a dep-node by calling `dep_node_fn`
+/// and push that onto the dep-graph stack of tasks, and also create a
+/// read edge from the corresponding AST node. This is used in
+/// compiler passes to automatically record the item that they are
+/// working on.
+pub fn visit_all_items_in_krate<'tcx,V,F>(tcx: &TyCtxt<'tcx>,
+                                          mut dep_node_fn: F,
+                                          visitor: &mut V)
+    where F: FnMut(DefId) -> DepNode<DefId>, V: Visitor<'tcx>
+{
+    struct TrackingVisitor<'visit, 'tcx: 'visit, F: 'visit, V: 'visit> {
+        tcx: &'visit TyCtxt<'tcx>,
+        dep_node_fn: &'visit mut F,
+        visitor: &'visit mut V
+    }
+
+    impl<'visit, 'tcx, F, V> Visitor<'tcx> for TrackingVisitor<'visit, 'tcx, F, V>
+        where F: FnMut(DefId) -> DepNode<DefId>, V: Visitor<'tcx>
+    {
+        fn visit_item(&mut self, i: &'tcx hir::Item) {
+            let item_def_id = self.tcx.map.local_def_id(i.id);
+            let task_id = (self.dep_node_fn)(item_def_id);
+            let _task = self.tcx.dep_graph.in_task(task_id);
+            debug!("Started task {:?}", task_id);
+            self.tcx.dep_graph.read(DepNode::Hir(item_def_id));
+            self.visitor.visit_item(i)
+        }
+    }
+
+    let krate = tcx.dep_graph.with_ignore(|| tcx.map.krate());
+    let mut tracking_visitor = TrackingVisitor {
+        tcx: tcx,
+        dep_node_fn: &mut dep_node_fn,
+        visitor: visitor
+    };
+    krate.visit_all_items(&mut tracking_visitor)
+}
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index e1b7afda58b..044fe7767f4 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -208,7 +208,7 @@ impl<'ast> Map<'ast> {
         self.dep_graph.read(self.dep_node(id));
     }
 
-    fn dep_node(&self, id0: NodeId) -> DepNode {
+    fn dep_node(&self, id0: NodeId) -> DepNode<DefId> {
         let map = self.map.borrow();
         let mut id = id0;
         loop {
diff --git a/src/librustc/ty/ivar.rs b/src/librustc/ty/ivar.rs
index b0f443fc19b..88327ab19a5 100644
--- a/src/librustc/ty/ivar.rs
+++ b/src/librustc/ty/ivar.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 use dep_graph::DepNode;
+use hir::def_id::DefId;
 use ty::{Ty, TyS};
 use ty::tls;
 
@@ -46,7 +47,7 @@ impl<'tcx, 'lt> TyIVar<'tcx, 'lt> {
     }
 
     #[inline]
-    pub fn get(&self, dep_node: DepNode) -> Option<Ty<'tcx>> {
+    pub fn get(&self, dep_node: DepNode<DefId>) -> Option<Ty<'tcx>> {
         tls::with(|tcx| tcx.dep_graph.read(dep_node));
         self.untracked_get()
     }
@@ -61,11 +62,11 @@ impl<'tcx, 'lt> TyIVar<'tcx, 'lt> {
     }
 
     #[inline]
-    pub fn unwrap(&self, dep_node: DepNode) -> Ty<'tcx> {
+    pub fn unwrap(&self, dep_node: DepNode<DefId>) -> Ty<'tcx> {
         self.get(dep_node).unwrap()
     }
 
-    pub fn fulfill(&self, dep_node: DepNode, value: Ty<'lt>) {
+    pub fn fulfill(&self, dep_node: DepNode<DefId>, value: Ty<'lt>) {
         tls::with(|tcx| tcx.dep_graph.write(dep_node));
 
         // Invariant (A) is fulfilled, because by (B), every alias
diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs
index 65a96e79ff4..57b1dd66bea 100644
--- a/src/librustc/ty/maps.rs
+++ b/src/librustc/ty/maps.rs
@@ -24,7 +24,7 @@ macro_rules! dep_map_ty {
         impl<'tcx> DepTrackingMapConfig for $ty_name<'tcx> {
             type Key = $key;
             type Value = $value;
-            fn to_dep_node(key: &$key) -> DepNode { DepNode::$node_name(*key) }
+            fn to_dep_node(key: &$key) -> DepNode<DefId> { DepNode::$node_name(*key) }
         }
     }
 }
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 444fea0918f..46615fca904 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -887,7 +887,7 @@ impl<'tcx> TraitPredicate<'tcx> {
     }
 
     /// Creates the dep-node for selecting/evaluating this trait reference.
-    fn dep_node(&self) -> DepNode {
+    fn dep_node(&self) -> DepNode<DefId> {
         DepNode::TraitSelect(self.def_id())
     }
 
@@ -906,7 +906,7 @@ impl<'tcx> PolyTraitPredicate<'tcx> {
         self.0.def_id()
     }
 
-    pub fn dep_node(&self) -> DepNode {
+    pub fn dep_node(&self) -> DepNode<DefId> {
         // ok to skip binder since depnode does not care about regions
         self.0.dep_node()
     }
@@ -2666,7 +2666,7 @@ impl<'tcx> TyCtxt<'tcx> {
     pub fn visit_all_items_in_krate<V,F>(&self,
                                          dep_node_fn: F,
                                          visitor: &mut V)
-        where F: FnMut(DefId) -> DepNode, V: Visitor<'tcx>
+        where F: FnMut(DefId) -> DepNode<DefId>, V: Visitor<'tcx>
     {
         dep_graph::visit_all_items_in_krate(self, dep_node_fn, visitor);
     }
diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs
index ce8ede7f4b9..11ac1fa8f82 100644
--- a/src/librustc_mir/transform/type_check.rs
+++ b/src/librustc_mir/transform/type_check.rs
@@ -584,7 +584,8 @@ impl<'tcx> MirPass<'tcx> for TypeckMir {
             // broken MIR, so try not to report duplicate errors.
             return;
         }
-        let _task = tcx.dep_graph.in_task(DepNode::MirTypeck(id));
+        let def_id = tcx.map.local_def_id(id);
+        let _task = tcx.dep_graph.in_task(DepNode::MirTypeck(def_id));
         let param_env = ty::ParameterEnvironment::for_item(tcx, id);
         let infcx = infer::new_infer_ctxt(tcx,
                                           &tcx.tables,
diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs
index 9bbc72eba36..c1802a5f0a9 100644
--- a/src/librustc_trans/context.rs
+++ b/src/librustc_trans/context.rs
@@ -179,7 +179,7 @@ pub struct TraitSelectionCache<'tcx> {
 impl<'tcx> DepTrackingMapConfig for TraitSelectionCache<'tcx> {
     type Key = ty::PolyTraitRef<'tcx>;
     type Value = traits::Vtable<'tcx, ()>;
-    fn to_dep_node(key: &ty::PolyTraitRef<'tcx>) -> DepNode {
+    fn to_dep_node(key: &ty::PolyTraitRef<'tcx>) -> DepNode<DefId> {
         ty::tls::with(|tcx| {
             let lifted_key = tcx.lift(key).unwrap();
             lifted_key.to_poly_trait_predicate().dep_node()