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
This commit is contained in:
parent
b1e68b9e2d
commit
a9b6205aff
207
src/librustc/dep_graph/dep_node.rs
Normal file
207
src/librustc/dep_graph/dep_node.rs
Normal file
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
@ -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> {
|
||||
|
@ -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();
|
||||
|
71
src/librustc/dep_graph/graph.rs
Normal file
71
src/librustc/dep_graph/graph.rs
Normal file
@ -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));
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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![]
|
||||
|
@ -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 }
|
||||
}
|
||||
|
@ -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
|
||||
|
56
src/librustc/dep_graph/visit.rs
Normal file
56
src/librustc/dep_graph/visit.rs
Normal file
@ -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)
|
||||
}
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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()
|
||||
|
Loading…
Reference in New Issue
Block a user