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 or the MIT license +// , 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 { + // 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 DepNode { + /// Used in testing + pub fn from_label_string(label: &str, data: D) -> Result, ()> { + 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(&self, mut op: OP) -> Option> + where OP: FnMut(&D) -> Option, 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 { 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; } impl DepTrackingMap { 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, - indices: FnvHashMap, +pub struct DepGraphEdges { + nodes: Vec>, + indices: FnvHashMap, IdIndex>, edges: FnvHashSet<(IdIndex, IdIndex)>, open_nodes: Vec, } @@ -40,8 +42,8 @@ enum OpenNode { Ignore, } -impl DepGraphEdges { - pub fn new() -> DepGraphEdges { +impl DepGraphEdges { + pub fn new() -> DepGraphEdges { 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 { + 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) -> 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) { 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) { 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) { 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) { 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 { 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 or the MIT license +// , 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 +} + +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(&self, op: OP) -> R + where OP: FnOnce() -> R + { + let _task = self.in_ignore(); + op() + } + + pub fn with_task(&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)); + } +} 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 -} - -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(&self, op: OP) -> R - where OP: FnOnce() -> R - { - let _task = self.in_ignore(); - op() - } - - pub fn with_task(&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, - pub indices: FnvHashMap, +pub struct DepGraphQuery { + pub graph: Graph, ()>, + pub indices: FnvHashMap, NodeIndex>, } -impl DepGraphQuery { - pub fn new(nodes: &[DepNode], edges: &[(DepNode, DepNode)]) -> DepGraphQuery { +impl DepGraphQuery { + pub fn new(nodes: &[DepNode], + edges: &[(DepNode, DepNode)]) + -> DepGraphQuery { let mut graph = Graph::new(); let mut indices = FnvHashMap(); for node in nodes { @@ -39,27 +43,43 @@ impl DepGraphQuery { } } - pub fn nodes(&self) -> Vec { + pub fn contains_node(&self, node: &DepNode) -> bool { + self.indices.contains_key(&node) + } + + pub fn nodes(&self) -> Vec> { self.graph.all_nodes() .iter() .map(|n| n.data.clone()) .collect() } - pub fn edges(&self) -> Vec<(DepNode,DepNode)> { + pub fn edges(&self) -> Vec<(DepNode,DepNode)> { 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 { + pub fn transitive_dependents(&self, node: DepNode) -> Vec> { 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) -> Vec> { + 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, } impl<'graph> DepTask<'graph> { - pub fn new(data: &'graph DepGraphThreadData, key: DepNode) -> DepTask<'graph> { + pub fn new(data: &'graph DepGraphThreadData, key: DepNode) + -> 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), + Write(DepNode), + PushTask(DepNode), + PopTask(DepNode), PushIgnore, PopIgnore, Query, @@ -57,7 +58,7 @@ pub struct DepGraphThreadData { swap_out: Sender>, // where to receive query results - query_in: Receiver, + query_in: Receiver>, } 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 { 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>, swap_out: Sender>, - query_out: Sender) { + query_out: Sender>) { 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 or the MIT license +// , 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, 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) +} 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 { 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> { + pub fn get(&self, dep_node: DepNode) -> Option> { 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) -> Ty<'tcx> { self.get(dep_node).unwrap() } - pub fn fulfill(&self, dep_node: DepNode, 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 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 { 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 { 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 { // 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(&self, dep_node_fn: F, visitor: &mut V) - where F: FnMut(DefId) -> DepNode, V: Visitor<'tcx> + where F: FnMut(DefId) -> DepNode, 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 { ty::tls::with(|tcx| { let lifted_key = tcx.lift(key).unwrap(); lifted_key.to_poly_trait_predicate().dep_node()