incr.comp.: Uniformly represent DepNodes as (Kind, StableHash) pairs.

This commit is contained in:
Michael Woerister 2017-06-02 17:36:30 +02:00
parent a7ac71b978
commit 3607174909
39 changed files with 860 additions and 717 deletions

View file

@ -12,7 +12,6 @@
use super::dep_node::DepNode;
use std::error::Error;
use std::fmt::Debug;
/// A dep-node filter goes from a user-defined string to a query over
/// nodes. Right now the format is like this:
@ -39,7 +38,7 @@ impl DepNodeFilter {
}
/// Tests whether `node` meets the filter, returning true if so.
pub fn test<D: Clone + Debug>(&self, node: &DepNode<D>) -> bool {
pub fn test(&self, node: &DepNode) -> bool {
let debug_str = format!("{:?}", node);
self.text.split("&")
.map(|s| s.trim())
@ -67,10 +66,10 @@ impl EdgeFilter {
}
}
pub fn test<D: Clone + Debug>(&self,
source: &DepNode<D>,
target: &DepNode<D>)
-> bool {
pub fn test(&self,
source: &DepNode,
target: &DepNode)
-> bool {
self.source.test(source) && self.target.test(target)
}
}

View file

@ -8,79 +8,280 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use hir::def_id::CrateNum;
use hir::def_id::{CrateNum, DefId};
use hir::map::DefPathHash;
use ich::Fingerprint;
use rustc_data_structures::stable_hasher::StableHasher;
use std::fmt::Debug;
use ty::TyCtxt;
use rustc_data_structures::stable_hasher::{StableHasher, HashStable};
use ich::StableHashingContext;
use std::hash::Hash;
macro_rules! try_opt {
($e:expr) => (
match $e {
Some(r) => r,
None => return None,
}
)
// erase!() just makes tokens go away. It's used to specify which macro argument
// is repeated (i.e. which sub-expression of the macro we are in) but don't need
// to actually use any of the arguments.
macro_rules! erase {
($x:tt) => ({})
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, 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`.
macro_rules! define_dep_nodes {
($(
$variant:ident $(( $($tuple_arg:tt),* ))*
$({ $($struct_arg_name:ident : $struct_arg_ty:ty),* })*
),*
) => (
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash,
RustcEncodable, RustcDecodable)]
pub enum DepKind {
$($variant),*
}
/// 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.hir.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.hir.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.
impl DepKind {
#[allow(unreachable_code)]
#[inline]
pub fn can_reconstruct_query_key(&self) -> bool {
match *self {
$(
DepKind :: $variant => {
// tuple args
$({
return <( $($tuple_arg,)* ) as DepNodeParams>
::CAN_RECONSTRUCT_QUERY_KEY;
})*
// struct args
$({
return <( $($struct_arg_ty,)* ) as DepNodeParams>
::CAN_RECONSTRUCT_QUERY_KEY;
})*
true
}
)*
}
}
#[allow(unreachable_code)]
#[inline]
pub fn has_params(&self) -> bool {
match *self {
$(
DepKind :: $variant => {
// tuple args
$({
$(erase!($tuple_arg);)*
return true;
})*
// struct args
$({
$(erase!($struct_arg_name);)*
return true;
})*
false
}
)*
}
}
}
pub enum DepConstructor {
$(
$variant $(( $($tuple_arg),* ))*
$({ $($struct_arg_name : $struct_arg_ty),* })*
),*
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash,
RustcEncodable, RustcDecodable)]
pub struct DepNode {
pub kind: DepKind,
pub hash: Fingerprint,
}
impl DepNode {
#[allow(unreachable_code, non_snake_case)]
pub fn new(tcx: TyCtxt, dep: DepConstructor) -> DepNode {
match dep {
$(
DepConstructor :: $variant $(( $($tuple_arg),* ))*
$({ $($struct_arg_name),* })*
=>
{
// tuple args
$({
let tupled_args = ( $($tuple_arg,)* );
let hash = DepNodeParams::to_fingerprint(&tupled_args,
tcx);
return DepNode {
kind: DepKind::$variant,
hash
};
})*
// struct args
$({
let tupled_args = ( $($struct_arg_name,)* );
let hash = DepNodeParams::to_fingerprint(&tupled_args,
tcx);
return DepNode {
kind: DepKind::$variant,
hash
};
})*
DepNode {
kind: DepKind::$variant,
hash: Fingerprint::zero(),
}
}
)*
}
}
/// Construct a DepNode from the given DepKind and DefPathHash. This
/// method will assert that the given DepKind actually requires a
/// single DefId/DefPathHash parameter.
#[inline]
pub fn from_def_path_hash(kind: DepKind,
def_path_hash: DefPathHash)
-> DepNode {
assert!(kind.can_reconstruct_query_key() && kind.has_params());
DepNode {
kind,
hash: def_path_hash.0,
}
}
/// Create a new, parameterless DepNode. This method will assert
/// that the DepNode corresponding to the given DepKind actually
/// does not require any parameters.
#[inline]
pub fn new_no_params(kind: DepKind) -> DepNode {
assert!(!kind.has_params());
DepNode {
kind,
hash: Fingerprint::zero(),
}
}
/// Extract the DefId corresponding to this DepNode. This will work
/// if two conditions are met:
///
/// 1. The Fingerprint of the DepNode actually is a DefPathHash, and
/// 2. the item that the DefPath refers to exists in the current tcx.
///
/// Condition (1) is determined by the DepKind variant of the
/// DepNode. Condition (2) might not be fulfilled if a DepNode
/// refers to something from the previous compilation session that
/// has been removed.
#[inline]
pub fn extract_def_id(&self, tcx: TyCtxt) -> Option<DefId> {
if self.kind.can_reconstruct_query_key() {
let def_path_hash = DefPathHash(self.hash);
tcx.def_path_hash_to_def_id
.as_ref()
.unwrap()
.get(&def_path_hash)
.cloned()
} else {
None
}
}
/// Used in testing
pub fn from_label_string(label: &str,
def_path_hash: DefPathHash)
-> Result<DepNode, ()> {
let kind = match label {
$(
stringify!($variant) => DepKind::$variant,
)*
_ => return Err(()),
};
if !kind.can_reconstruct_query_key() {
return Err(());
}
if kind.has_params() {
Ok(def_path_hash.to_dep_node(kind))
} else {
Ok(DepNode::new_no_params(kind))
}
}
}
);
}
impl DefPathHash {
#[inline]
pub fn to_dep_node(self, kind: DepKind) -> DepNode {
DepNode::from_def_path_hash(kind, self)
}
}
impl DefId {
#[inline]
pub fn to_dep_node(self, tcx: TyCtxt, kind: DepKind) -> DepNode {
DepNode::from_def_path_hash(kind, tcx.def_path_hash(self))
}
}
define_dep_nodes!(
// 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.hir.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.hir.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 the HIR node with the given node-id
Hir(DefId),
/// Represents the body of a function or method. The def-id is that of the
/// function/method.
HirBody(D),
// Represents the body of a function or method. The def-id is that of the
// function/method.
HirBody(DefId),
/// Represents the metadata for a given HIR node, typically found
/// in an extern crate.
MetaData(D),
// Represents the metadata for a given HIR node, typically found
// in an extern crate.
MetaData(DefId),
/// Represents some artifact that we save to disk. Note that these
/// do not have a def-id as part of their identifier.
// Represents some artifact that we save to disk. Note that these
// do not have a def-id as part of their identifier.
WorkProduct(WorkProductId),
// Represents different phases in the compiler.
RegionMaps(D),
RegionMaps(DefId),
Coherence,
Resolve,
CoherenceCheckTrait(D),
CoherenceCheckImpl(D),
CoherenceOverlapCheck(D),
CoherenceOverlapCheckSpecial(D),
CoherenceCheckTrait(DefId),
CoherenceCheckImpl(DefId),
CoherenceOverlapCheck(DefId),
CoherenceOverlapCheckSpecial(DefId),
Variance,
PrivacyAccessLevels(CrateNum),
// Represents the MIR for a fn; also used as the task node for
// things read/modify that MIR.
MirKrate,
Mir(D),
MirShim(Vec<D>),
Mir(DefId),
MirShim(DefIdList),
BorrowCheckKrate,
BorrowCheck(D),
RvalueCheck(D),
BorrowCheck(DefId),
RvalueCheck(DefId),
Reachability,
MirKeys,
LateLintCheck,
TransCrateItem(D),
TransCrateItem(DefId),
TransWriteMetadata,
CrateVariances,
@ -89,38 +290,38 @@ pub enum DepNode<D: Clone + Debug> {
// 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`).
AssociatedItems(D),
ItemSignature(D),
ItemVarianceConstraints(D),
ItemVariances(D),
IsForeignItem(D),
TypeParamPredicates((D, D)),
SizedConstraint(D),
DtorckConstraint(D),
AdtDestructor(D),
AssociatedItemDefIds(D),
InherentImpls(D),
AssociatedItems(DefId),
ItemSignature(DefId),
ItemVarianceConstraints(DefId),
ItemVariances(DefId),
IsForeignItem(DefId),
TypeParamPredicates { item_id: DefId, param_id: DefId },
SizedConstraint(DefId),
DtorckConstraint(DefId),
AdtDestructor(DefId),
AssociatedItemDefIds(DefId),
InherentImpls(DefId),
TypeckBodiesKrate,
TypeckTables(D),
UsedTraitImports(D),
ConstEval(D),
SymbolName(D),
SpecializationGraph(D),
ObjectSafety(D),
IsCopy(D),
IsSized(D),
IsFreeze(D),
NeedsDrop(D),
Layout(D),
TypeckTables(DefId),
UsedTraitImports(DefId),
ConstEval(DefId),
SymbolName(DefId),
SpecializationGraph(DefId),
ObjectSafety(DefId),
IsCopy(DefId),
IsSized(DefId),
IsFreeze(DefId),
NeedsDrop(DefId),
Layout(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(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(DefId),
AllLocalTraitImpls,
@ -129,184 +330,80 @@ pub enum DepNode<D: Clone + Debug> {
// 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),
TraitItems(DefId),
ReprHints(DefId),
/// Trait selection cache is a little funny. Given a trait
/// reference like `Foo: SomeTrait<Bar>`, there could be
/// arbitrarily many def-ids to map on in there (e.g., `Foo`,
/// `SomeTrait`, `Bar`). We could have a vector of them, but it
/// requires heap-allocation, and trait sel in general can be a
/// surprisingly hot path. So instead we pick two def-ids: the
/// trait def-id, and the first def-id in the input types. If there
/// is no def-id in the input types, then we use the trait def-id
/// again. So for example:
///
/// - `i32: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Clone }`
/// - `u32: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Clone }`
/// - `Clone: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Clone }`
/// - `Vec<i32>: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Vec }`
/// - `String: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: String }`
/// - `Foo: Trait<Bar>` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }`
/// - `Foo: Trait<i32>` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }`
/// - `(Foo, Bar): Trait` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }`
/// - `i32: Trait<Foo>` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }`
///
/// You can see that we map many trait refs to the same
/// trait-select node. This is not a problem, it just means
/// imprecision in our dep-graph tracking. The important thing is
/// that for any given trait-ref, we always map to the **same**
/// trait-select node.
TraitSelect { trait_def_id: D, input_def_id: D },
// Trait selection cache is a little funny. Given a trait
// reference like `Foo: SomeTrait<Bar>`, there could be
// arbitrarily many def-ids to map on in there (e.g., `Foo`,
// `SomeTrait`, `Bar`). We could have a vector of them, but it
// requires heap-allocation, and trait sel in general can be a
// surprisingly hot path. So instead we pick two def-ids: the
// trait def-id, and the first def-id in the input types. If there
// is no def-id in the input types, then we use the trait def-id
// again. So for example:
//
// - `i32: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Clone }`
// - `u32: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Clone }`
// - `Clone: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Clone }`
// - `Vec<i32>: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Vec }`
// - `String: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: String }`
// - `Foo: Trait<Bar>` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }`
// - `Foo: Trait<i32>` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }`
// - `(Foo, Bar): Trait` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }`
// - `i32: Trait<Foo>` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }`
//
// You can see that we map many trait refs to the same
// trait-select node. This is not a problem, it just means
// imprecision in our dep-graph tracking. The important thing is
// that for any given trait-ref, we always map to the **same**
// trait-select node.
TraitSelect { trait_def_id: DefId, input_def_id: DefId },
/// For proj. cache, we just keep a list of all def-ids, since it is
/// not a hotspot.
ProjectionCache { def_ids: Vec<D> },
// For proj. cache, we just keep a list of all def-ids, since it is
// not a hotspot.
ProjectionCache { def_ids: DefIdList },
ParamEnv(D),
DescribeDef(D),
DefSpan(D),
Stability(D),
Deprecation(D),
ItemBodyNestedBodies(D),
ConstIsRvaluePromotableToStatic(D),
ImplParent(D),
TraitOfItem(D),
IsExportedSymbol(D),
IsMirAvailable(D),
ItemAttrs(D),
FnArgNames(D),
ParamEnv(DefId),
DescribeDef(DefId),
DefSpan(DefId),
Stability(DefId),
Deprecation(DefId),
ItemBodyNestedBodies(DefId),
ConstIsRvaluePromotableToStatic(DefId),
ImplParent(DefId),
TraitOfItem(DefId),
IsExportedSymbol(DefId),
IsMirAvailable(DefId),
ItemAttrs(DefId),
FnArgNames(DefId)
);
trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> {
const CAN_RECONSTRUCT_QUERY_KEY: bool;
fn to_fingerprint(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Fingerprint;
}
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(())
}
}
}
impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a, T> DepNodeParams<'a, 'gcx, 'tcx> for T
where T: HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
{
default const CAN_RECONSTRUCT_QUERY_KEY: bool = false;
if label == "Krate" {
// special case
return Ok(DepNode::Krate);
}
default fn to_fingerprint(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Fingerprint {
let mut hcx = StableHashingContext::new(tcx);
let mut hasher = StableHasher::new();
check! {
BorrowCheck,
Hir,
HirBody,
TransCrateItem,
AssociatedItems,
ItemSignature,
ItemVariances,
IsForeignItem,
AssociatedItemDefIds,
InherentImpls,
TypeckTables,
UsedTraitImports,
TraitImpls,
ReprHints,
}
self.hash_stable(&mut hcx, &mut hasher);
hasher.finish()
}
}
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::*;
impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> DepNodeParams<'a, 'gcx, 'tcx> for (DefId,) {
const CAN_RECONSTRUCT_QUERY_KEY: bool = true;
match *self {
Krate => Some(Krate),
BorrowCheckKrate => Some(BorrowCheckKrate),
MirKrate => Some(MirKrate),
TypeckBodiesKrate => Some(TypeckBodiesKrate),
Coherence => Some(Coherence),
CrateVariances => Some(CrateVariances),
Resolve => Some(Resolve),
Variance => Some(Variance),
PrivacyAccessLevels(k) => Some(PrivacyAccessLevels(k)),
Reachability => Some(Reachability),
MirKeys => Some(MirKeys),
LateLintCheck => Some(LateLintCheck),
TransWriteMetadata => Some(TransWriteMetadata),
// work product names do not need to be mapped, because
// they are always absolute.
WorkProduct(ref id) => Some(WorkProduct(id.clone())),
IsCopy(ref d) => op(d).map(IsCopy),
IsSized(ref d) => op(d).map(IsSized),
IsFreeze(ref d) => op(d).map(IsFreeze),
NeedsDrop(ref d) => op(d).map(NeedsDrop),
Layout(ref d) => op(d).map(Layout),
Hir(ref d) => op(d).map(Hir),
HirBody(ref d) => op(d).map(HirBody),
MetaData(ref d) => op(d).map(MetaData),
CoherenceCheckTrait(ref d) => op(d).map(CoherenceCheckTrait),
CoherenceCheckImpl(ref d) => op(d).map(CoherenceCheckImpl),
CoherenceOverlapCheck(ref d) => op(d).map(CoherenceOverlapCheck),
CoherenceOverlapCheckSpecial(ref d) => op(d).map(CoherenceOverlapCheckSpecial),
Mir(ref d) => op(d).map(Mir),
MirShim(ref def_ids) => {
let def_ids: Option<Vec<E>> = def_ids.iter().map(op).collect();
def_ids.map(MirShim)
}
BorrowCheck(ref d) => op(d).map(BorrowCheck),
RegionMaps(ref d) => op(d).map(RegionMaps),
RvalueCheck(ref d) => op(d).map(RvalueCheck),
TransCrateItem(ref d) => op(d).map(TransCrateItem),
AssociatedItems(ref d) => op(d).map(AssociatedItems),
ItemSignature(ref d) => op(d).map(ItemSignature),
ItemVariances(ref d) => op(d).map(ItemVariances),
ItemVarianceConstraints(ref d) => op(d).map(ItemVarianceConstraints),
IsForeignItem(ref d) => op(d).map(IsForeignItem),
TypeParamPredicates((ref item, ref param)) => {
Some(TypeParamPredicates((try_opt!(op(item)), try_opt!(op(param)))))
}
SizedConstraint(ref d) => op(d).map(SizedConstraint),
DtorckConstraint(ref d) => op(d).map(DtorckConstraint),
AdtDestructor(ref d) => op(d).map(AdtDestructor),
AssociatedItemDefIds(ref d) => op(d).map(AssociatedItemDefIds),
InherentImpls(ref d) => op(d).map(InherentImpls),
TypeckTables(ref d) => op(d).map(TypeckTables),
UsedTraitImports(ref d) => op(d).map(UsedTraitImports),
ConstEval(ref d) => op(d).map(ConstEval),
SymbolName(ref d) => op(d).map(SymbolName),
SpecializationGraph(ref d) => op(d).map(SpecializationGraph),
ObjectSafety(ref d) => op(d).map(ObjectSafety),
TraitImpls(ref d) => op(d).map(TraitImpls),
AllLocalTraitImpls => Some(AllLocalTraitImpls),
TraitItems(ref d) => op(d).map(TraitItems),
ReprHints(ref d) => op(d).map(ReprHints),
TraitSelect { ref trait_def_id, ref input_def_id } => {
op(trait_def_id).and_then(|trait_def_id| {
op(input_def_id).and_then(|input_def_id| {
Some(TraitSelect { trait_def_id: trait_def_id,
input_def_id: input_def_id })
})
})
}
ProjectionCache { ref def_ids } => {
let def_ids: Option<Vec<E>> = def_ids.iter().map(op).collect();
def_ids.map(|d| ProjectionCache { def_ids: d })
}
ParamEnv(ref d) => op(d).map(ParamEnv),
DescribeDef(ref d) => op(d).map(DescribeDef),
DefSpan(ref d) => op(d).map(DefSpan),
Stability(ref d) => op(d).map(Stability),
Deprecation(ref d) => op(d).map(Deprecation),
ItemAttrs(ref d) => op(d).map(ItemAttrs),
FnArgNames(ref d) => op(d).map(FnArgNames),
ImplParent(ref d) => op(d).map(ImplParent),
TraitOfItem(ref d) => op(d).map(TraitOfItem),
IsExportedSymbol(ref d) => op(d).map(IsExportedSymbol),
ItemBodyNestedBodies(ref d) => op(d).map(ItemBodyNestedBodies),
ConstIsRvaluePromotableToStatic(ref d) => op(d).map(ConstIsRvaluePromotableToStatic),
IsMirAvailable(ref d) => op(d).map(IsMirAvailable),
}
fn to_fingerprint(&self, tcx: TyCtxt) -> Fingerprint {
tcx.def_path_hash(self.0).0
}
}
@ -315,14 +412,38 @@ impl<D: Clone + Debug> DepNode<D> {
/// some independent path or string that persists between runs without
/// the need to be mapped or unmapped. (This ensures we can serialize
/// them even in the absence of a tcx.)
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
pub struct WorkProductId(pub Fingerprint);
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash,
RustcEncodable, RustcDecodable)]
pub struct WorkProductId {
hash: Fingerprint
}
impl WorkProductId {
pub fn from_cgu_name(cgu_name: &str) -> WorkProductId {
let mut hasher = StableHasher::new();
cgu_name.len().hash(&mut hasher);
cgu_name.hash(&mut hasher);
WorkProductId(hasher.finish())
WorkProductId {
hash: hasher.finish()
}
}
pub fn from_fingerprint(fingerprint: Fingerprint) -> WorkProductId {
WorkProductId {
hash: fingerprint
}
}
pub fn to_dep_node(self) -> DepNode {
DepNode {
kind: DepKind::WorkProduct,
hash: self.hash,
}
}
}
impl_stable_hash_for!(struct ::dep_graph::WorkProductId {
hash
});
type DefIdList = Vec<DefId>;

View file

@ -8,12 +8,11 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use hir::def_id::DefId;
use rustc_data_structures::fx::FxHashMap;
use std::cell::RefCell;
use std::ops::Index;
use std::hash::Hash;
use std::marker::PhantomData;
use ty::TyCtxt;
use util::common::MemoizationMap;
use super::{DepNode, DepGraph};
@ -30,7 +29,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<DefId>;
fn to_dep_node(tcx: TyCtxt, key: &Self::Key) -> DepNode;
}
impl<M: DepTrackingMapConfig> DepTrackingMap<M> {
@ -44,18 +43,18 @@ impl<M: DepTrackingMapConfig> DepTrackingMap<M> {
/// Registers a (synthetic) read from the key `k`. Usually this
/// is invoked automatically by `get`.
fn read(&self, k: &M::Key) {
let dep_node = M::to_dep_node(k);
fn read(&self, tcx: TyCtxt, k: &M::Key) {
let dep_node = M::to_dep_node(tcx, k);
self.graph.read(dep_node);
}
pub fn get(&self, k: &M::Key) -> Option<&M::Value> {
self.read(k);
pub fn get(&self, tcx: TyCtxt, k: &M::Key) -> Option<&M::Value> {
self.read(tcx, k);
self.map.get(k)
}
pub fn contains_key(&self, k: &M::Key) -> bool {
self.read(k);
pub fn contains_key(&self, tcx: TyCtxt, k: &M::Key) -> bool {
self.read(tcx, k);
self.map.contains_key(k)
}
@ -99,32 +98,22 @@ impl<M: DepTrackingMapConfig> MemoizationMap for RefCell<DepTrackingMap<M>> {
/// The key is the line marked `(*)`: the closure implicitly
/// accesses the body of the item `item`, so we register a read
/// from `Hir(item_def_id)`.
fn memoize<OP>(&self, key: M::Key, op: OP) -> M::Value
fn memoize<OP>(&self, tcx: TyCtxt, key: M::Key, op: OP) -> M::Value
where OP: FnOnce() -> M::Value
{
let graph;
{
let this = self.borrow();
if let Some(result) = this.map.get(&key) {
this.read(&key);
this.read(tcx, &key);
return result.clone();
}
graph = this.graph.clone();
}
let _task = graph.in_task(M::to_dep_node(&key));
let _task = graph.in_task(M::to_dep_node(tcx, &key));
let result = op();
self.borrow_mut().map.insert(key, result.clone());
result
}
}
impl<'k, M: DepTrackingMapConfig> Index<&'k M::Key> for DepTrackingMap<M> {
type Output = M::Value;
#[inline]
fn index(&self, k: &'k M::Key) -> &M::Value {
self.get(k).unwrap()
}
}

View file

@ -9,13 +9,11 @@
// except according to those terms.
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use std::fmt::Debug;
use std::hash::Hash;
use super::{DepGraphQuery, DepNode};
pub struct DepGraphEdges<D: Clone + Debug + Eq + Hash> {
nodes: Vec<DepNode<D>>,
indices: FxHashMap<DepNode<D>, IdIndex>,
pub struct DepGraphEdges {
nodes: Vec<DepNode>,
indices: FxHashMap<DepNode, IdIndex>,
edges: FxHashSet<(IdIndex, IdIndex)>,
open_nodes: Vec<OpenNode>,
}
@ -42,8 +40,8 @@ enum OpenNode {
Ignore,
}
impl<D: Clone + Debug + Eq + Hash> DepGraphEdges<D> {
pub fn new() -> DepGraphEdges<D> {
impl DepGraphEdges {
pub fn new() -> DepGraphEdges {
DepGraphEdges {
nodes: vec![],
indices: FxHashMap(),
@ -52,12 +50,12 @@ impl<D: Clone + Debug + Eq + Hash> DepGraphEdges<D> {
}
}
fn id(&self, index: IdIndex) -> DepNode<D> {
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<D>) -> IdIndex {
fn make_node(&mut self, id: DepNode) -> IdIndex {
if let Some(&i) = self.indices.get(&id) {
return i;
}
@ -82,7 +80,7 @@ impl<D: Clone + Debug + Eq + Hash> DepGraphEdges<D> {
assert_eq!(popped_node, OpenNode::Ignore);
}
pub fn push_task(&mut self, key: DepNode<D>) {
pub fn push_task(&mut self, key: DepNode) {
let top_node = self.current_node();
let new_node = self.make_node(key);
@ -95,7 +93,7 @@ impl<D: Clone + Debug + Eq + Hash> DepGraphEdges<D> {
}
}
pub fn pop_task(&mut self, key: DepNode<D>) {
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);
}
@ -105,7 +103,7 @@ impl<D: Clone + Debug + Eq + Hash> DepGraphEdges<D> {
/// effect. Note that *reading* from tracked state is harmless if
/// you are not in a task; what is bad is *writing* to tracked
/// state (and leaking data that you read into a tracked task).
pub fn read(&mut self, v: DepNode<D>) {
pub fn read(&mut self, v: DepNode) {
if self.current_node().is_some() {
let source = self.make_node(v);
self.add_edge_from_current_node(|current| (source, current))
@ -115,7 +113,7 @@ impl<D: Clone + Debug + Eq + Hash> DepGraphEdges<D> {
/// 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<D>) {
pub fn write(&mut self, v: DepNode) {
let target = self.make_node(v);
self.add_edge_from_current_node(|current| (current, target))
}
@ -159,7 +157,7 @@ impl<D: Clone + Debug + Eq + Hash> DepGraphEdges<D> {
}
}
pub fn query(&self) -> DepGraphQuery<D> {
pub fn query(&self) -> DepGraphQuery {
let edges: Vec<_> = self.edges.iter()
.map(|&(i, j)| (self.id(i), self.id(j)))
.collect();

View file

@ -8,7 +8,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use hir::def_id::DefId;
use rustc_data_structures::fx::FxHashMap;
use session::config::OutputType;
use std::cell::{Ref, RefCell};
@ -57,7 +56,7 @@ impl DepGraph {
self.data.thread.is_fully_enabled()
}
pub fn query(&self) -> DepGraphQuery<DefId> {
pub fn query(&self) -> DepGraphQuery {
self.data.thread.query()
}
@ -65,7 +64,7 @@ impl DepGraph {
raii::IgnoreTask::new(&self.data.thread)
}
pub fn in_task<'graph>(&'graph self, key: DepNode<DefId>) -> Option<raii::DepTask<'graph>> {
pub fn in_task<'graph>(&'graph self, key: DepNode) -> Option<raii::DepTask<'graph>> {
raii::DepTask::new(&self.data.thread, key)
}
@ -103,14 +102,14 @@ impl DepGraph {
/// `arg` parameter.
///
/// [README]: README.md
pub fn with_task<C, A, R>(&self, key: DepNode<DefId>, cx: C, arg: A, task: fn(C, A) -> R) -> R
pub fn with_task<C, A, R>(&self, key: DepNode, cx: C, arg: A, task: fn(C, A) -> R) -> R
where C: DepGraphSafe, A: DepGraphSafe
{
let _task = self.in_task(key);
task(cx, arg)
}
pub fn read(&self, v: DepNode<DefId>) {
pub fn read(&self, v: DepNode) {
if self.data.thread.is_enqueue_enabled() {
self.data.thread.enqueue(DepMessage::Read(v));
}

View file

@ -28,3 +28,5 @@ pub use self::query::DepGraphQuery;
pub use self::safe::AssertDepGraphSafe;
pub use self::safe::DepGraphSafe;
pub use self::raii::DepTask;
pub use self::dep_node::{DepKind, DepConstructor};

View file

@ -10,20 +10,18 @@
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::graph::{Direction, INCOMING, Graph, NodeIndex, OUTGOING};
use std::fmt::Debug;
use std::hash::Hash;
use super::DepNode;
pub struct DepGraphQuery<D: Clone + Debug + Hash + Eq> {
pub graph: Graph<DepNode<D>, ()>,
pub indices: FxHashMap<DepNode<D>, NodeIndex>,
pub struct DepGraphQuery {
pub graph: Graph<DepNode, ()>,
pub indices: FxHashMap<DepNode, NodeIndex>,
}
impl<D: Clone + Debug + Hash + Eq> DepGraphQuery<D> {
pub fn new(nodes: &[DepNode<D>],
edges: &[(DepNode<D>, DepNode<D>)])
-> DepGraphQuery<D> {
impl DepGraphQuery {
pub fn new(nodes: &[DepNode],
edges: &[(DepNode, DepNode)])
-> DepGraphQuery {
let mut graph = Graph::new();
let mut indices = FxHashMap();
for node in nodes {
@ -43,18 +41,18 @@ impl<D: Clone + Debug + Hash + Eq> DepGraphQuery<D> {
}
}
pub fn contains_node(&self, node: &DepNode<D>) -> bool {
pub fn contains_node(&self, node: &DepNode) -> bool {
self.indices.contains_key(&node)
}
pub fn nodes(&self) -> Vec<&DepNode<D>> {
pub fn nodes(&self) -> Vec<&DepNode> {
self.graph.all_nodes()
.iter()
.map(|n| &n.data)
.collect()
}
pub fn edges(&self) -> Vec<(&DepNode<D>,&DepNode<D>)> {
pub fn edges(&self) -> Vec<(&DepNode,&DepNode)> {
self.graph.all_edges()
.iter()
.map(|edge| (edge.source(), edge.target()))
@ -63,7 +61,7 @@ impl<D: Clone + Debug + Hash + Eq> DepGraphQuery<D> {
.collect()
}
fn reachable_nodes(&self, node: &DepNode<D>, direction: Direction) -> Vec<&DepNode<D>> {
fn reachable_nodes(&self, node: &DepNode, direction: Direction) -> Vec<&DepNode> {
if let Some(&index) = self.indices.get(node) {
self.graph.depth_traverse(index, direction)
.map(|s| self.graph.node_data(s))
@ -75,17 +73,17 @@ impl<D: Clone + Debug + Hash + Eq> DepGraphQuery<D> {
/// All nodes reachable from `node`. In other words, things that
/// will have to be recomputed if `node` changes.
pub fn transitive_successors(&self, node: &DepNode<D>) -> Vec<&DepNode<D>> {
pub fn transitive_successors(&self, node: &DepNode) -> Vec<&DepNode> {
self.reachable_nodes(node, OUTGOING)
}
/// All nodes that can reach `node`.
pub fn transitive_predecessors(&self, node: &DepNode<D>) -> Vec<&DepNode<D>> {
pub fn transitive_predecessors(&self, node: &DepNode) -> Vec<&DepNode> {
self.reachable_nodes(node, INCOMING)
}
/// Just the outgoing edges from `node`.
pub fn immediate_successors(&self, node: &DepNode<D>) -> Vec<&DepNode<D>> {
pub fn immediate_successors(&self, node: &DepNode) -> Vec<&DepNode> {
if let Some(&index) = self.indices.get(&node) {
self.graph.successor_nodes(index)
.map(|s| self.graph.node_data(s))

View file

@ -8,17 +8,16 @@
// 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: Option<DepNode<DefId>>,
key: Option<DepNode>,
}
impl<'graph> DepTask<'graph> {
pub fn new(data: &'graph DepGraphThreadData, key: DepNode<DefId>)
pub fn new(data: &'graph DepGraphThreadData, key: DepNode)
-> Option<DepTask<'graph>> {
if data.is_enqueue_enabled() {
data.enqueue(DepMessage::PushTask(key.clone()));

View file

@ -26,7 +26,6 @@
//! specify an edge filter to be applied to each edge as it is
//! created. See `./README.md` for details.
use hir::def_id::DefId;
use std::cell::RefCell;
use std::env;
@ -36,7 +35,7 @@ use super::debug::EdgeFilter;
pub struct ShadowGraph {
// if you push None onto the stack, that corresponds to an Ignore
stack: RefCell<Vec<Option<DepNode<DefId>>>>,
stack: RefCell<Vec<Option<DepNode>>>,
forbidden_edge: Option<EdgeFilter>,
}
@ -114,8 +113,8 @@ impl ShadowGraph {
}
fn check_edge(&self,
source: Option<Option<&DepNode<DefId>>>,
target: Option<Option<&DepNode<DefId>>>) {
source: Option<Option<&DepNode>>,
target: Option<Option<&DepNode>>) {
assert!(ENABLED);
match (source, target) {
// cannot happen, one side is always Some(Some(_))
@ -141,9 +140,9 @@ impl ShadowGraph {
// Do a little juggling: we get back a reference to an option at the
// top of the stack, convert it to an optional reference.
fn top<'s>(stack: &'s Vec<Option<DepNode<DefId>>>) -> Option<Option<&'s DepNode<DefId>>> {
fn top<'s>(stack: &'s Vec<Option<DepNode>>) -> Option<Option<&'s DepNode>> {
stack.last()
.map(|n: &'s Option<DepNode<DefId>>| -> Option<&'s DepNode<DefId>> {
.map(|n: &'s Option<DepNode>| -> Option<&'s DepNode> {
// (*)
// (*) type annotation just there to clarify what would
// otherwise be some *really* obscure code

View file

@ -18,7 +18,6 @@
//! 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::sync::mpsc::{self, Sender, Receiver};
use std::thread;
@ -30,10 +29,10 @@ use super::shadow::ShadowGraph;
#[derive(Debug)]
pub enum DepMessage {
Read(DepNode<DefId>),
Write(DepNode<DefId>),
PushTask(DepNode<DefId>),
PopTask(DepNode<DefId>),
Read(DepNode),
Write(DepNode),
PushTask(DepNode),
PopTask(DepNode),
PushIgnore,
PopIgnore,
Query,
@ -63,7 +62,7 @@ pub struct DepGraphThreadData {
swap_out: Sender<Vec<DepMessage>>,
// where to receive query results
query_in: Receiver<DepGraphQuery<DefId>>,
query_in: Receiver<DepGraphQuery>,
}
const INITIAL_CAPACITY: usize = 2048;
@ -120,7 +119,7 @@ impl DepGraphThreadData {
self.swap_out.send(old_messages).unwrap();
}
pub fn query(&self) -> DepGraphQuery<DefId> {
pub fn query(&self) -> DepGraphQuery {
assert!(self.is_fully_enabled(), "should never query if not fully enabled");
self.enqueue(DepMessage::Query);
self.swap();
@ -151,7 +150,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<DefId>>) {
query_out: Sender<DepGraphQuery>) {
let mut edges = DepGraphEdges::new();
// the compiler thread always expects a fresh buffer to be

View file

@ -15,7 +15,7 @@ pub use self::def_collector::{DefCollector, MacroInvocationData};
pub use self::definitions::{Definitions, DefKey, DefPath, DefPathData,
DisambiguatedDefPathData, DefPathHash};
use dep_graph::{DepGraph, DepNode};
use dep_graph::{DepGraph, DepNode, DepKind};
use hir::def_id::{CRATE_DEF_INDEX, DefId, DefIndex, DefIndexAddressSpace};
@ -235,7 +235,7 @@ impl Forest {
}
pub fn krate<'hir>(&'hir self) -> &'hir Crate {
self.dep_graph.read(DepNode::Krate);
self.dep_graph.read(DepNode::new_no_params(DepKind::Krate));
&self.krate
}
}
@ -280,7 +280,7 @@ impl<'hir> Map<'hir> {
self.dep_graph.read(self.dep_node(id));
}
fn dep_node(&self, id0: NodeId) -> DepNode<DefId> {
fn dep_node(&self, id0: NodeId) -> DepNode {
let mut id = id0;
let mut last_expr = None;
loop {
@ -289,14 +289,16 @@ impl<'hir> Map<'hir> {
EntryItem(..) |
EntryTraitItem(..) |
EntryImplItem(..) => {
let def_index = self.definitions.opt_def_index(id).unwrap();
let def_path_hash = self.definitions.def_path_hash(def_index);
if let Some(last_id) = last_expr {
// The body may have a separate dep node
if entry.is_body_owner(last_id) {
let def_id = self.local_def_id(id);
return DepNode::HirBody(def_id);
return def_path_hash.to_dep_node(DepKind::HirBody);
}
}
return DepNode::Hir(self.local_def_id(id));
return def_path_hash.to_dep_node(DepKind::Hir);
}
EntryVariant(p, v) => {
@ -305,8 +307,9 @@ impl<'hir> Map<'hir> {
if last_expr.is_some() {
if v.node.disr_expr.map(|e| e.node_id) == last_expr {
// The enum parent holds both Hir and HirBody nodes.
let def_id = self.local_def_id(id);
return DepNode::HirBody(def_id);
let def_index = self.definitions.opt_def_index(id).unwrap();
let def_path_hash = self.definitions.def_path_hash(def_index);
return def_path_hash.to_dep_node(DepKind::HirBody);
}
}
}
@ -331,7 +334,8 @@ impl<'hir> Map<'hir> {
}
RootCrate => {
return DepNode::Hir(DefId::local(CRATE_DEF_INDEX));
let def_path_hash = self.definitions.def_path_hash(CRATE_DEF_INDEX);
return def_path_hash.to_dep_node(DepKind::Hir);
}
NotPresent =>
@ -339,8 +343,11 @@ impl<'hir> Map<'hir> {
// present in the map for whatever reason, but
// they *do* have def-ids. So if we encounter an
// empty hole, check for that case.
return self.opt_local_def_id(id)
.map(|def_id| DepNode::Hir(def_id))
return self.definitions.opt_def_index(id)
.map(|def_index| {
let def_path_hash = self.definitions.def_path_hash(def_index);
def_path_hash.to_dep_node(DepKind::Hir)
})
.unwrap_or_else(|| {
bug!("Walking parents from `{}` \
led to `NotPresent` at `{}`",
@ -497,7 +504,7 @@ impl<'hir> Map<'hir> {
}
pub fn trait_impls(&self, trait_did: DefId) -> &'hir [NodeId] {
self.dep_graph.read(DepNode::AllLocalTraitImpls);
self.dep_graph.read(DepNode::new_no_params(DepKind::AllLocalTraitImpls));
// NB: intentionally bypass `self.forest.krate()` so that we
// do not trigger a read of the whole krate here
@ -505,7 +512,7 @@ impl<'hir> Map<'hir> {
}
pub fn trait_default_impl(&self, trait_did: DefId) -> Option<NodeId> {
self.dep_graph.read(DepNode::AllLocalTraitImpls);
self.dep_graph.read(DepNode::new_no_params(DepKind::AllLocalTraitImpls));
// NB: intentionally bypass `self.forest.krate()` so that we
// do not trigger a read of the whole krate here
@ -520,8 +527,9 @@ impl<'hir> Map<'hir> {
/// invoking `krate.attrs` because it registers a tighter
/// dep-graph access.
pub fn krate_attrs(&self) -> &'hir [ast::Attribute] {
let crate_root_def_id = DefId::local(CRATE_DEF_INDEX);
self.dep_graph.read(DepNode::Hir(crate_root_def_id));
let def_path_hash = self.definitions.def_path_hash(CRATE_DEF_INDEX);
self.dep_graph.read(def_path_hash.to_dep_node(DepKind::Hir));
&self.forest.krate.attrs
}
@ -754,11 +762,8 @@ impl<'hir> Map<'hir> {
}
}
pub fn get_inlined_body(&self, def_id: DefId) -> Option<&'hir Body> {
self.inlined_bodies.borrow().get(&def_id).map(|&body| {
self.dep_graph.read(DepNode::MetaData(def_id));
body
})
pub fn get_inlined_body_untracked(&self, def_id: DefId) -> Option<&'hir Body> {
self.inlined_bodies.borrow().get(&def_id).cloned()
}
pub fn intern_inlined_body(&self, def_id: DefId, body: Body) -> &'hir Body {

View file

@ -25,7 +25,7 @@
//! for all lint attributes.
use self::TargetLint::*;
use dep_graph::DepNode;
use dep_graph::{DepNode, DepKind};
use middle::privacy::AccessLevels;
use ty::{self, TyCtxt};
use session::{config, early_error, Session};
@ -1321,7 +1321,7 @@ fn check_lint_name_cmdline(sess: &Session, lint_cx: &LintStore,
///
/// Consumes the `lint_store` field of the `Session`.
pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
let _task = tcx.dep_graph.in_task(DepNode::LateLintCheck);
let _task = tcx.dep_graph.in_task(DepNode::new_no_params(DepKind::LateLintCheck));
let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE);

View file

@ -183,7 +183,9 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
assert!(!infcx.is_in_snapshot());
if infcx.tcx.fulfilled_predicates.borrow().check_duplicate(&obligation.predicate) {
let tcx = infcx.tcx;
if tcx.fulfilled_predicates.borrow().check_duplicate(tcx, &obligation.predicate) {
debug!("register_predicate_obligation: duplicate");
return
}
@ -373,7 +375,8 @@ fn process_predicate<'a, 'gcx, 'tcx>(
match obligation.predicate {
ty::Predicate::Trait(ref data) => {
if selcx.tcx().fulfilled_predicates.borrow().check_duplicate_trait(data) {
let tcx = selcx.tcx();
if tcx.fulfilled_predicates.borrow().check_duplicate_trait(tcx, data) {
return Ok(Some(vec![]));
}
@ -607,22 +610,22 @@ impl<'a, 'gcx, 'tcx> GlobalFulfilledPredicates<'gcx> {
}
}
pub fn check_duplicate(&self, key: &ty::Predicate<'tcx>) -> bool {
pub fn check_duplicate(&self, tcx: TyCtxt, key: &ty::Predicate<'tcx>) -> bool {
if let ty::Predicate::Trait(ref data) = *key {
self.check_duplicate_trait(data)
self.check_duplicate_trait(tcx, data)
} else {
false
}
}
pub fn check_duplicate_trait(&self, data: &ty::PolyTraitPredicate<'tcx>) -> bool {
pub fn check_duplicate_trait(&self, tcx: TyCtxt, data: &ty::PolyTraitPredicate<'tcx>) -> bool {
// For the global predicate registry, when we find a match, it
// may have been computed by some other task, so we want to
// add a read from the node corresponding to the predicate
// processing to make sure we get the transitive dependencies.
if self.set.contains(data) {
debug_assert!(data.is_global());
self.dep_graph.read(data.dep_node());
self.dep_graph.read(data.dep_node(tcx));
debug!("check_duplicate: global predicate `{:?}` already proved elsewhere", data);
true

View file

@ -381,7 +381,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
assert!(!obligation.predicate.has_escaping_regions());
let tcx = self.tcx();
let dep_node = obligation.predicate.dep_node();
let dep_node = obligation.predicate.dep_node(tcx);
let _task = tcx.dep_graph.in_task(dep_node);
let stack = self.push_stack(TraitObligationStackList::empty(), obligation);
@ -514,11 +514,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
debug!("evaluate_predicate_recursively({:?})",
obligation);
let tcx = self.tcx();
// Check the cache from the tcx of predicates that we know
// have been proven elsewhere. This cache only contains
// predicates that are global in scope and hence unaffected by
// the current environment.
if self.tcx().fulfilled_predicates.borrow().check_duplicate(&obligation.predicate) {
if tcx.fulfilled_predicates.borrow().check_duplicate(tcx, &obligation.predicate) {
return EvaluatedToOk;
}

View file

@ -13,7 +13,8 @@
// seems likely that they should eventually be merged into more
// general routines.
use dep_graph::{DepGraph, DepNode, DepTrackingMap, DepTrackingMapConfig};
use dep_graph::{DepGraph, DepNode, DepTrackingMap, DepTrackingMapConfig,
DepConstructor};
use hir::def_id::DefId;
use infer::TransNormalize;
use std::cell::RefCell;
@ -40,7 +41,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
// Remove any references to regions; this helps improve caching.
let trait_ref = self.erase_regions(&trait_ref);
self.trans_trait_caches.trait_cache.memoize(trait_ref, || {
self.trans_trait_caches.trait_cache.memoize(self, trait_ref, || {
debug!("trans::fulfill_obligation(trait_ref={:?}, def_id={:?})",
trait_ref, trait_ref.def_id());
@ -138,7 +139,7 @@ impl<'a, 'gcx> TypeFolder<'gcx, 'gcx> for AssociatedTypeNormalizer<'a, 'gcx> {
if !ty.has_projection_types() {
ty
} else {
self.tcx.trans_trait_caches.project_cache.memoize(ty, || {
self.tcx.trans_trait_caches.project_cache.memoize(self.tcx, ty, || {
debug!("AssociatedTypeNormalizer: ty={:?}", ty);
self.tcx.normalize_associated_type(&ty)
})
@ -170,8 +171,8 @@ pub struct TraitSelectionCache<'tcx> {
impl<'tcx> DepTrackingMapConfig for TraitSelectionCache<'tcx> {
type Key = ty::PolyTraitRef<'tcx>;
type Value = Vtable<'tcx, ()>;
fn to_dep_node(key: &ty::PolyTraitRef<'tcx>) -> DepNode<DefId> {
key.to_poly_trait_predicate().dep_node()
fn to_dep_node(tcx: TyCtxt, key: &ty::PolyTraitRef<'tcx>) -> DepNode {
key.to_poly_trait_predicate().dep_node(tcx)
}
}
@ -184,7 +185,7 @@ pub struct ProjectionCache<'gcx> {
impl<'gcx> DepTrackingMapConfig for ProjectionCache<'gcx> {
type Key = Ty<'gcx>;
type Value = Ty<'gcx>;
fn to_dep_node(key: &Self::Key) -> DepNode<DefId> {
fn to_dep_node(tcx: TyCtxt, key: &Self::Key) -> DepNode {
// Ideally, we'd just put `key` into the dep-node, but we
// can't put full types in there. So just collect up all the
// def-ids of structs/enums as well as any traits that we
@ -208,7 +209,7 @@ impl<'gcx> DepTrackingMapConfig for ProjectionCache<'gcx> {
})
.collect();
DepNode::ProjectionCache { def_ids: def_ids }
DepNode::new(tcx, DepConstructor::ProjectionCache { def_ids: def_ids })
}
}

View file

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use dep_graph::DepNode;
use dep_graph::DepConstructor;
use hir::def_id::DefId;
use ty::{self, Ty, TypeFoldable, Substs};
use util::ppaux;
@ -60,7 +60,8 @@ impl<'tcx> InstanceDef<'tcx> {
tcx.get_attrs(self.def_id())
}
pub(crate) fn dep_node(&self) -> DepNode<DefId> {
pub //(crate)
fn dep_node(&self) -> DepConstructor {
// HACK: def-id binning, project-style; someone replace this with
// real on-demand.
let ty = match self {
@ -69,7 +70,7 @@ impl<'tcx> InstanceDef<'tcx> {
_ => None
}.into_iter();
DepNode::MirShim(
DepConstructor::MirShim(
Some(self.def_id()).into_iter().chain(
ty.flat_map(|t| t.walk()).flat_map(|t| match t.sty {
ty::TyAdt(adt_def, _) => Some(adt_def.did),

View file

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use dep_graph::{DepNode, DepTrackingMapConfig};
use dep_graph::{DepConstructor, DepNode, DepTrackingMapConfig};
use hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId, LOCAL_CRATE};
use hir::def::Def;
use hir;
@ -524,10 +524,10 @@ macro_rules! define_maps {
type Value = $V;
#[allow(unused)]
fn to_dep_node(key: &$K) -> DepNode<DefId> {
use dep_graph::DepNode::*;
fn to_dep_node(tcx: TyCtxt, key: &$K) -> DepNode {
use dep_graph::DepConstructor::*;
$node(*key)
DepNode::new(tcx, $node(*key))
}
}
impl<'a, $tcx, 'lcx> queries::$name<$tcx> {
@ -554,7 +554,7 @@ macro_rules! define_maps {
span = key.default_span(tcx)
}
let _task = tcx.dep_graph.in_task(Self::to_dep_node(&key));
let _task = tcx.dep_graph.in_task(Self::to_dep_node(tcx, &key));
let result = tcx.cycle_check(span, Query::$name(key), || {
let provider = tcx.maps.providers[key.map_crate()].$name;
@ -569,7 +569,7 @@ macro_rules! define_maps {
// We register the `read` here, but not in `force`, since
// `force` does not give access to the value produced (and thus
// we actually don't read it).
tcx.dep_graph.read(Self::to_dep_node(&key));
tcx.dep_graph.read(Self::to_dep_node(tcx, &key));
Self::try_get_with(tcx, span, key, Clone::clone)
}
@ -782,7 +782,7 @@ define_maps! { <'tcx>
/// To avoid cycles within the predicates of a single item we compute
/// per-type-parameter predicates for resolving `T::AssocTy`.
[] type_param_predicates: TypeParamPredicates((DefId, DefId))
[] type_param_predicates: type_param_predicates((DefId, DefId))
-> ty::GenericPredicates<'tcx>,
[] trait_def: ItemSignature(DefId) -> &'tcx ty::TraitDef,
@ -931,74 +931,81 @@ define_maps! { <'tcx>
-> Result<&'tcx Layout, LayoutError<'tcx>>,
}
fn coherent_trait_dep_node((_, def_id): (CrateNum, DefId)) -> DepNode<DefId> {
DepNode::CoherenceCheckTrait(def_id)
fn type_param_predicates((item_id, param_id): (DefId, DefId)) -> DepConstructor {
DepConstructor::TypeParamPredicates {
item_id,
param_id
}
}
fn crate_inherent_impls_dep_node(_: CrateNum) -> DepNode<DefId> {
DepNode::Coherence
fn coherent_trait_dep_node((_, def_id): (CrateNum, DefId)) -> DepConstructor {
DepConstructor::CoherenceCheckTrait(def_id)
}
fn reachability_dep_node(_: CrateNum) -> DepNode<DefId> {
DepNode::Reachability
fn crate_inherent_impls_dep_node(_: CrateNum) -> DepConstructor {
DepConstructor::Coherence
}
fn mir_shim_dep_node(instance: ty::InstanceDef) -> DepNode<DefId> {
fn reachability_dep_node(_: CrateNum) -> DepConstructor {
DepConstructor::Reachability
}
fn mir_shim_dep_node(instance: ty::InstanceDef) -> DepConstructor {
instance.dep_node()
}
fn symbol_name_dep_node(instance: ty::Instance) -> DepNode<DefId> {
fn symbol_name_dep_node(instance: ty::Instance) -> DepConstructor {
// symbol_name uses the substs only to traverse them to find the
// hash, and that does not create any new dep-nodes.
DepNode::SymbolName(instance.def.def_id())
DepConstructor::SymbolName(instance.def.def_id())
}
fn typeck_item_bodies_dep_node(_: CrateNum) -> DepNode<DefId> {
DepNode::TypeckBodiesKrate
fn typeck_item_bodies_dep_node(_: CrateNum) -> DepConstructor {
DepConstructor::TypeckBodiesKrate
}
fn const_eval_dep_node((def_id, _): (DefId, &Substs)) -> DepNode<DefId> {
DepNode::ConstEval(def_id)
fn const_eval_dep_node((def_id, _): (DefId, &Substs)) -> DepConstructor {
DepConstructor::ConstEval(def_id)
}
fn mir_keys(_: CrateNum) -> DepNode<DefId> {
DepNode::MirKeys
fn mir_keys(_: CrateNum) -> DepConstructor {
DepConstructor::MirKeys
}
fn crate_variances(_: CrateNum) -> DepNode<DefId> {
DepNode::CrateVariances
fn crate_variances(_: CrateNum) -> DepConstructor {
DepConstructor::CrateVariances
}
fn relevant_trait_impls_for((def_id, _): (DefId, SimplifiedType)) -> DepNode<DefId> {
DepNode::TraitImpls(def_id)
fn relevant_trait_impls_for((def_id, _): (DefId, SimplifiedType)) -> DepConstructor {
DepConstructor::TraitImpls(def_id)
}
fn is_copy_dep_node<'tcx>(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepNode<DefId> {
fn is_copy_dep_node<'tcx>(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor {
let def_id = ty::item_path::characteristic_def_id_of_type(key.value)
.unwrap_or(DefId::local(CRATE_DEF_INDEX));
DepNode::IsCopy(def_id)
DepConstructor::IsCopy(def_id)
}
fn is_sized_dep_node<'tcx>(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepNode<DefId> {
fn is_sized_dep_node<'tcx>(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor {
let def_id = ty::item_path::characteristic_def_id_of_type(key.value)
.unwrap_or(DefId::local(CRATE_DEF_INDEX));
DepNode::IsSized(def_id)
DepConstructor::IsSized(def_id)
}
fn is_freeze_dep_node<'tcx>(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepNode<DefId> {
fn is_freeze_dep_node<'tcx>(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor {
let def_id = ty::item_path::characteristic_def_id_of_type(key.value)
.unwrap_or(DefId::local(CRATE_DEF_INDEX));
DepNode::IsFreeze(def_id)
DepConstructor::IsFreeze(def_id)
}
fn needs_drop_dep_node<'tcx>(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepNode<DefId> {
fn needs_drop_dep_node<'tcx>(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor {
let def_id = ty::item_path::characteristic_def_id_of_type(key.value)
.unwrap_or(DefId::local(CRATE_DEF_INDEX));
DepNode::NeedsDrop(def_id)
DepConstructor::NeedsDrop(def_id)
}
fn layout_dep_node<'tcx>(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepNode<DefId> {
fn layout_dep_node<'tcx>(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor {
let def_id = ty::item_path::characteristic_def_id_of_type(key.value)
.unwrap_or(DefId::local(CRATE_DEF_INDEX));
DepNode::Layout(def_id)
DepConstructor::Layout(def_id)
}

View file

@ -15,7 +15,7 @@ pub use self::IntVarValue::*;
pub use self::LvaluePreference::*;
pub use self::fold::TypeFoldable;
use dep_graph::DepNode;
use dep_graph::{DepNode, DepConstructor};
use hir::{map as hir_map, FreevarMap, TraitMap};
use hir::def::{Def, CtorKind, ExportMap};
use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
@ -918,7 +918,7 @@ impl<'tcx> TraitPredicate<'tcx> {
}
/// Creates the dep-node for selecting/evaluating this trait reference.
fn dep_node(&self) -> DepNode<DefId> {
fn dep_node(&self, tcx: TyCtxt) -> DepNode {
// Extact the trait-def and first def-id from inputs. See the
// docs for `DepNode::TraitSelect` for more information.
let trait_def_id = self.def_id();
@ -931,10 +931,10 @@ impl<'tcx> TraitPredicate<'tcx> {
})
.next()
.unwrap_or(trait_def_id);
DepNode::TraitSelect {
DepNode::new(tcx, DepConstructor::TraitSelect {
trait_def_id: trait_def_id,
input_def_id: input_def_id
}
})
}
pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a {
@ -952,9 +952,9 @@ impl<'tcx> PolyTraitPredicate<'tcx> {
self.0.def_id()
}
pub fn dep_node(&self) -> DepNode<DefId> {
pub fn dep_node(&self, tcx: TyCtxt) -> DepNode {
// ok to skip binder since depnode does not care about regions
self.0.dep_node()
self.0.dep_node(tcx)
}
}

View file

@ -19,6 +19,8 @@ use std::iter::repeat;
use std::path::Path;
use std::time::{Duration, Instant};
use ty::TyCtxt;
// The name of the associated type for `Fn` return types
pub const FN_OUTPUT_NAME: &'static str = "Output";
@ -209,7 +211,7 @@ pub trait MemoizationMap {
/// needed in the `op` to ensure that the correct edges are
/// added into the dep graph. See the `DepTrackingMap` impl for
/// more details!
fn memoize<OP>(&self, key: Self::Key, op: OP) -> Self::Value
fn memoize<OP>(&self, tcx: TyCtxt, key: Self::Key, op: OP) -> Self::Value
where OP: FnOnce() -> Self::Value;
}
@ -219,7 +221,7 @@ impl<K, V, S> MemoizationMap for RefCell<HashMap<K,V,S>>
type Key = K;
type Value = V;
fn memoize<OP>(&self, key: K, op: OP) -> V
fn memoize<OP>(&self, _tcx: TyCtxt, key: K, op: OP) -> V
where OP: FnOnce() -> V
{
let result = self.borrow().get(&key).cloned();

View file

@ -44,7 +44,7 @@
//! ```
use graphviz as dot;
use rustc::dep_graph::{DepGraphQuery, DepNode};
use rustc::dep_graph::{DepGraphQuery, DepNode, DepKind};
use rustc::dep_graph::debug::{DepNodeFilter, EdgeFilter};
use rustc::hir::def_id::DefId;
use rustc::ty::TyCtxt;
@ -95,8 +95,8 @@ pub fn assert_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
check_paths(tcx, &if_this_changed, &then_this_would_need);
}
type Sources = Vec<(Span, DefId, DepNode<DefId>)>;
type Targets = Vec<(Span, ast::Name, ast::NodeId, DepNode<DefId>)>;
type Sources = Vec<(Span, DefId, DepNode)>;
type Targets = Vec<(Span, ast::Name, ast::NodeId, DepNode)>;
struct IfThisChanged<'a, 'tcx:'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
@ -121,13 +121,14 @@ impl<'a, 'tcx> IfThisChanged<'a, 'tcx> {
fn process_attrs(&mut self, node_id: ast::NodeId, attrs: &[ast::Attribute]) {
let def_id = self.tcx.hir.local_def_id(node_id);
let def_path_hash = self.tcx.def_path_hash(def_id);
for attr in attrs {
if attr.check_name(ATTR_IF_THIS_CHANGED) {
let dep_node_interned = self.argument(attr);
let dep_node = match dep_node_interned {
None => DepNode::Hir(def_id),
None => def_path_hash.to_dep_node(DepKind::Hir),
Some(n) => {
match DepNode::from_label_string(&n.as_str(), def_id) {
match DepNode::from_label_string(&n.as_str(), def_path_hash) {
Ok(n) => n,
Err(()) => {
self.tcx.sess.span_fatal(
@ -142,7 +143,7 @@ impl<'a, 'tcx> IfThisChanged<'a, 'tcx> {
let dep_node_interned = self.argument(attr);
let dep_node = match dep_node_interned {
Some(n) => {
match DepNode::from_label_string(&n.as_str(), def_id) {
match DepNode::from_label_string(&n.as_str(), def_path_hash) {
Ok(n) => n,
Err(()) => {
self.tcx.sess.span_fatal(
@ -263,34 +264,34 @@ fn dump_graph(tcx: TyCtxt) {
}
}
pub struct GraphvizDepGraph<'q>(FxHashSet<&'q DepNode<DefId>>,
Vec<(&'q DepNode<DefId>, &'q DepNode<DefId>)>);
pub struct GraphvizDepGraph<'q>(FxHashSet<&'q DepNode>,
Vec<(&'q DepNode, &'q DepNode)>);
impl<'a, 'tcx, 'q> dot::GraphWalk<'a> for GraphvizDepGraph<'q> {
type Node = &'q DepNode<DefId>;
type Edge = (&'q DepNode<DefId>, &'q DepNode<DefId>);
fn nodes(&self) -> dot::Nodes<&'q DepNode<DefId>> {
type Node = &'q DepNode;
type Edge = (&'q DepNode, &'q DepNode);
fn nodes(&self) -> dot::Nodes<&'q DepNode> {
let nodes: Vec<_> = self.0.iter().cloned().collect();
nodes.into_cow()
}
fn edges(&self) -> dot::Edges<(&'q DepNode<DefId>, &'q DepNode<DefId>)> {
fn edges(&self) -> dot::Edges<(&'q DepNode, &'q DepNode)> {
self.1[..].into_cow()
}
fn source(&self, edge: &(&'q DepNode<DefId>, &'q DepNode<DefId>)) -> &'q DepNode<DefId> {
fn source(&self, edge: &(&'q DepNode, &'q DepNode)) -> &'q DepNode {
edge.0
}
fn target(&self, edge: &(&'q DepNode<DefId>, &'q DepNode<DefId>)) -> &'q DepNode<DefId> {
fn target(&self, edge: &(&'q DepNode, &'q DepNode)) -> &'q DepNode {
edge.1
}
}
impl<'a, 'tcx, 'q> dot::Labeller<'a> for GraphvizDepGraph<'q> {
type Node = &'q DepNode<DefId>;
type Edge = (&'q DepNode<DefId>, &'q DepNode<DefId>);
type Node = &'q DepNode;
type Edge = (&'q DepNode, &'q DepNode);
fn graph_id(&self) -> dot::Id {
dot::Id::new("DependencyGraph").unwrap()
}
fn node_id(&self, n: &&'q DepNode<DefId>) -> dot::Id {
fn node_id(&self, n: &&'q DepNode) -> dot::Id {
let s: String =
format!("{:?}", n).chars()
.map(|c| if c == '_' || c.is_alphanumeric() { c } else { '_' })
@ -298,7 +299,7 @@ impl<'a, 'tcx, 'q> dot::Labeller<'a> for GraphvizDepGraph<'q> {
debug!("n={:?} s={:?}", n, s);
dot::Id::new(s).unwrap()
}
fn node_label(&self, n: &&'q DepNode<DefId>) -> dot::LabelText {
fn node_label(&self, n: &&'q DepNode) -> dot::LabelText {
dot::LabelText::label(format!("{:?}", n))
}
}
@ -306,8 +307,8 @@ impl<'a, 'tcx, 'q> dot::Labeller<'a> for GraphvizDepGraph<'q> {
// Given an optional filter like `"x,y,z"`, returns either `None` (no
// filter) or the set of nodes whose labels contain all of those
// substrings.
fn node_set<'q>(query: &'q DepGraphQuery<DefId>, filter: &DepNodeFilter)
-> Option<FxHashSet<&'q DepNode<DefId>>>
fn node_set<'q>(query: &'q DepGraphQuery, filter: &DepNodeFilter)
-> Option<FxHashSet<&'q DepNode>>
{
debug!("node_set(filter={:?})", filter);
@ -318,10 +319,10 @@ fn node_set<'q>(query: &'q DepGraphQuery<DefId>, filter: &DepNodeFilter)
Some(query.nodes().into_iter().filter(|n| filter.test(n)).collect())
}
fn filter_nodes<'q>(query: &'q DepGraphQuery<DefId>,
sources: &Option<FxHashSet<&'q DepNode<DefId>>>,
targets: &Option<FxHashSet<&'q DepNode<DefId>>>)
-> FxHashSet<&'q DepNode<DefId>>
fn filter_nodes<'q>(query: &'q DepGraphQuery,
sources: &Option<FxHashSet<&'q DepNode>>,
targets: &Option<FxHashSet<&'q DepNode>>)
-> FxHashSet<&'q DepNode>
{
if let &Some(ref sources) = sources {
if let &Some(ref targets) = targets {
@ -336,10 +337,10 @@ fn filter_nodes<'q>(query: &'q DepGraphQuery<DefId>,
}
}
fn walk_nodes<'q>(query: &'q DepGraphQuery<DefId>,
starts: &FxHashSet<&'q DepNode<DefId>>,
fn walk_nodes<'q>(query: &'q DepGraphQuery,
starts: &FxHashSet<&'q DepNode>,
direction: Direction)
-> FxHashSet<&'q DepNode<DefId>>
-> FxHashSet<&'q DepNode>
{
let mut set = FxHashSet();
for &start in starts {
@ -360,10 +361,10 @@ fn walk_nodes<'q>(query: &'q DepGraphQuery<DefId>,
set
}
fn walk_between<'q>(query: &'q DepGraphQuery<DefId>,
sources: &FxHashSet<&'q DepNode<DefId>>,
targets: &FxHashSet<&'q DepNode<DefId>>)
-> FxHashSet<&'q DepNode<DefId>>
fn walk_between<'q>(query: &'q DepGraphQuery,
sources: &FxHashSet<&'q DepNode>,
targets: &FxHashSet<&'q DepNode>)
-> FxHashSet<&'q DepNode>
{
// This is a bit tricky. We want to include a node only if it is:
// (a) reachable from a source and (b) will reach a target. And we
@ -391,7 +392,7 @@ fn walk_between<'q>(query: &'q DepGraphQuery<DefId>,
})
.collect();
fn recurse(query: &DepGraphQuery<DefId>,
fn recurse(query: &DepGraphQuery,
node_states: &mut [State],
node: NodeIndex)
-> bool
@ -428,9 +429,9 @@ fn walk_between<'q>(query: &'q DepGraphQuery<DefId>,
}
}
fn filter_edges<'q>(query: &'q DepGraphQuery<DefId>,
nodes: &FxHashSet<&'q DepNode<DefId>>)
-> Vec<(&'q DepNode<DefId>, &'q DepNode<DefId>)>
fn filter_edges<'q>(query: &'q DepGraphQuery,
nodes: &FxHashSet<&'q DepNode>)
-> Vec<(&'q DepNode, &'q DepNode)>
{
query.edges()
.into_iter()

View file

@ -29,7 +29,7 @@
use std::cell::RefCell;
use std::hash::Hash;
use rustc::dep_graph::DepNode;
use rustc::dep_graph::{DepNode, DepKind};
use rustc::hir;
use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
use rustc::hir::map::DefPathHash;
@ -44,7 +44,7 @@ use rustc_data_structures::accumulate_vec::AccumulateVec;
pub type IchHasher = StableHasher<Fingerprint>;
pub struct IncrementalHashesMap {
hashes: FxHashMap<DepNode<DefId>, Fingerprint>,
hashes: FxHashMap<DepNode, Fingerprint>,
// These are the metadata hashes for the current crate as they were stored
// during the last compilation session. They are only loaded if
@ -62,16 +62,16 @@ impl IncrementalHashesMap {
}
}
pub fn get(&self, k: &DepNode<DefId>) -> Option<&Fingerprint> {
pub fn get(&self, k: &DepNode) -> Option<&Fingerprint> {
self.hashes.get(k)
}
pub fn insert(&mut self, k: DepNode<DefId>, v: Fingerprint) -> Option<Fingerprint> {
self.hashes.insert(k, v)
pub fn insert(&mut self, k: DepNode, v: Fingerprint) {
assert!(self.hashes.insert(k, v).is_none());
}
pub fn iter<'a>(&'a self)
-> ::std::collections::hash_map::Iter<'a, DepNode<DefId>, Fingerprint> {
-> ::std::collections::hash_map::Iter<'a, DepNode, Fingerprint> {
self.hashes.iter()
}
@ -80,10 +80,10 @@ impl IncrementalHashesMap {
}
}
impl<'a> ::std::ops::Index<&'a DepNode<DefId>> for IncrementalHashesMap {
impl<'a> ::std::ops::Index<&'a DepNode> for IncrementalHashesMap {
type Output = Fingerprint;
fn index(&self, index: &'a DepNode<DefId>) -> &Fingerprint {
fn index(&self, index: &'a DepNode) -> &Fingerprint {
match self.hashes.get(index) {
Some(fingerprint) => fingerprint,
None => {
@ -100,7 +100,7 @@ struct ComputeItemHashesVisitor<'a, 'tcx: 'a> {
impl<'a, 'tcx: 'a> ComputeItemHashesVisitor<'a, 'tcx> {
fn compute_and_store_ich_for_item_like<T>(&mut self,
dep_node: DepNode<DefId>,
dep_node: DepNode,
hash_bodies: bool,
item_like: T)
where T: HashStable<StableHashingContext<'a, 'tcx, 'tcx>>
@ -143,36 +143,29 @@ impl<'a, 'tcx: 'a> ComputeItemHashesVisitor<'a, 'tcx> {
// add each item (in some deterministic order) to the overall
// crate hash.
{
let hcx = &mut self.hcx;
let mut item_hashes: Vec<_> =
self.hashes.iter()
.filter_map(|(item_dep_node, &item_hash)| {
.filter_map(|(&item_dep_node, &item_hash)| {
// This `match` determines what kinds of nodes
// go into the SVH:
match *item_dep_node {
DepNode::Hir(_) |
DepNode::HirBody(_) => {
match item_dep_node.kind {
DepKind::Hir |
DepKind::HirBody => {
// We want to incoporate these into the
// SVH.
}
DepNode::AllLocalTraitImpls => {
DepKind::AllLocalTraitImpls => {
// These are already covered by hashing
// the HIR.
return None
}
ref other => {
bug!("Found unexpected DepNode during \
bug!("Found unexpected DepKind during \
SVH computation: {:?}",
other)
}
}
// Convert from a DepNode<DefId> to a
// DepNode<u64> where the u64 is the hash of
// the def-id's def-path:
let item_dep_node =
item_dep_node.map_def(|&did| Some(hcx.def_path_hash(did)))
.unwrap();
Some((item_dep_node, item_hash))
})
.collect();
@ -183,7 +176,7 @@ impl<'a, 'tcx: 'a> ComputeItemHashesVisitor<'a, 'tcx> {
krate.attrs.hash_stable(&mut self.hcx, &mut crate_state);
let crate_hash = crate_state.finish();
self.hashes.insert(DepNode::Krate, crate_hash);
self.hashes.insert(DepNode::new_no_params(DepKind::Krate), crate_hash);
debug!("calculate_crate_hash: crate_hash={:?}", crate_hash);
}
@ -206,11 +199,11 @@ impl<'a, 'tcx: 'a> ComputeItemHashesVisitor<'a, 'tcx> {
body_ids: _,
} = *krate;
let def_id = DefId::local(CRATE_DEF_INDEX);
self.compute_and_store_ich_for_item_like(DepNode::Hir(def_id),
let def_path_hash = self.hcx.tcx().hir.definitions().def_path_hash(CRATE_DEF_INDEX);
self.compute_and_store_ich_for_item_like(def_path_hash.to_dep_node(DepKind::Hir),
false,
(module, (span, attrs)));
self.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id),
self.compute_and_store_ich_for_item_like(def_path_hash.to_dep_node(DepKind::HirBody),
true,
(module, (span, attrs)));
}
@ -255,27 +248,43 @@ impl<'a, 'tcx: 'a> ComputeItemHashesVisitor<'a, 'tcx> {
let mut hasher = StableHasher::new();
impls.hash_stable(&mut self.hcx, &mut hasher);
self.hashes.insert(DepNode::AllLocalTraitImpls, hasher.finish());
self.hashes.insert(DepNode::new_no_params(DepKind::AllLocalTraitImpls),
hasher.finish());
}
}
impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for ComputeItemHashesVisitor<'a, 'tcx> {
fn visit_item(&mut self, item: &'tcx hir::Item) {
let def_id = self.hcx.tcx().hir.local_def_id(item.id);
self.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), false, item);
self.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), true, item);
let def_path_hash = self.hcx.tcx().def_path_hash(def_id);
self.compute_and_store_ich_for_item_like(def_path_hash.to_dep_node(DepKind::Hir),
false,
item);
self.compute_and_store_ich_for_item_like(def_path_hash.to_dep_node(DepKind::HirBody),
true,
item);
}
fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem) {
let def_id = self.hcx.tcx().hir.local_def_id(item.id);
self.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), false, item);
self.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), true, item);
let def_path_hash = self.hcx.tcx().def_path_hash(def_id);
self.compute_and_store_ich_for_item_like(def_path_hash.to_dep_node(DepKind::Hir),
false,
item);
self.compute_and_store_ich_for_item_like(def_path_hash.to_dep_node(DepKind::HirBody),
true,
item);
}
fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem) {
let def_id = self.hcx.tcx().hir.local_def_id(item.id);
self.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), false, item);
self.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), true, item);
let def_path_hash = self.hcx.tcx().def_path_hash(def_id);
self.compute_and_store_ich_for_item_like(def_path_hash.to_dep_node(DepKind::Hir),
false,
item);
self.compute_and_store_ich_for_item_like(def_path_hash.to_dep_node(DepKind::HirBody),
true,
item);
}
}
@ -297,8 +306,13 @@ pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
for macro_def in krate.exported_macros.iter() {
let def_id = tcx.hir.local_def_id(macro_def.id);
visitor.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), false, macro_def);
visitor.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), true, macro_def);
let def_path_hash = tcx.def_path_hash(def_id);
visitor.compute_and_store_ich_for_item_like(def_path_hash.to_dep_node(DepKind::Hir),
false,
macro_def);
visitor.compute_and_store_ich_for_item_like(def_path_hash.to_dep_node(DepKind::HirBody),
true,
macro_def);
}
visitor.compute_and_store_ich_for_trait_impls(krate);

View file

@ -22,7 +22,7 @@ use rustc_data_structures::indexed_vec::{IndexVec, Idx};
#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct SerializedDepGraph {
/// The set of all DepNodes in the graph
pub nodes: IndexVec<DepNodeIndex, DepNode<DefPathHash>>,
pub nodes: IndexVec<DepNodeIndex, DepNode>,
/// For each DepNode, stores the list of edges originating from that
/// DepNode. Encoded as a [start, end) pair indexing into edge_list_data,
/// which holds the actual DepNodeIndices of the target nodes.
@ -34,7 +34,7 @@ pub struct SerializedDepGraph {
/// These are output nodes that have no incoming edges. We track
/// these separately so that when we reload all edges, we don't
/// lose track of these nodes.
pub bootstrap_outputs: Vec<DepNode<DefPathHash>>,
pub bootstrap_outputs: Vec<DepNode>,
/// These are hashes of two things:
/// - the HIR nodes in this crate
@ -87,7 +87,7 @@ impl Idx for DepNodeIndex {
#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct SerializedHash {
/// def-id of thing being hashed
pub dep_node: DepNode<DefPathHash>,
pub dep_node: DepNode,
/// the hash as of previous compilation, computed by code in
/// `hash` module

View file

@ -41,7 +41,7 @@
//!
use super::load::DirtyNodes;
use rustc::dep_graph::{DepGraphQuery, DepNode};
use rustc::dep_graph::{DepGraphQuery, DepNode, DepKind};
use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::hir::itemlikevisit::ItemLikeVisitor;
@ -64,14 +64,10 @@ pub fn check_dirty_clean_annotations<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
let _ignore = tcx.dep_graph.in_ignore();
let def_path_hash_to_def_id = tcx.def_path_hash_to_def_id.as_ref().unwrap();
let dirty_inputs: FxHashSet<DepNode<DefId>> =
let dirty_inputs: FxHashSet<DepNode> =
dirty_inputs.keys()
.filter_map(|dep_node| {
dep_node.map_def(|def_path_hash| {
def_path_hash_to_def_id.get(def_path_hash).cloned()
})
})
.filter(|dep_node| dep_node.extract_def_id(tcx).is_some())
.cloned()
.collect();
let query = tcx.dep_graph.query();
@ -100,18 +96,19 @@ pub fn check_dirty_clean_annotations<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
pub struct DirtyCleanVisitor<'a, 'tcx:'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
query: &'a DepGraphQuery<DefId>,
dirty_inputs: FxHashSet<DepNode<DefId>>,
query: &'a DepGraphQuery,
dirty_inputs: FxHashSet<DepNode>,
checked_attrs: FxHashSet<ast::AttrId>,
}
impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
fn dep_node(&self, attr: &Attribute, def_id: DefId) -> DepNode<DefId> {
fn dep_node(&self, attr: &Attribute, def_id: DefId) -> DepNode {
let def_path_hash = self.tcx.def_path_hash(def_id);
for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
if item.check_name(LABEL) {
let value = expect_associated_value(self.tcx, &item);
match DepNode::from_label_string(&value.as_str(), def_id) {
Ok(def_id) => return def_id,
match DepNode::from_label_string(&value.as_str(), def_path_hash) {
Ok(dep_node) => return dep_node,
Err(()) => {
self.tcx.sess.span_fatal(
item.span,
@ -124,24 +121,30 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
self.tcx.sess.span_fatal(attr.span, "no `label` found");
}
fn dep_node_str(&self, dep_node: &DepNode<DefId>) -> DepNode<String> {
dep_node.map_def(|&def_id| Some(self.tcx.item_path_str(def_id))).unwrap()
fn dep_node_str(&self, dep_node: &DepNode) -> String {
if let Some(def_id) = dep_node.extract_def_id(self.tcx) {
format!("{:?}({})",
dep_node.kind,
self.tcx.item_path_str(def_id))
} else {
format!("{:?}({:?})", dep_node.kind, dep_node.hash)
}
}
fn assert_dirty(&self, item_span: Span, dep_node: DepNode<DefId>) {
fn assert_dirty(&self, item_span: Span, dep_node: DepNode) {
debug!("assert_dirty({:?})", dep_node);
match dep_node {
DepNode::Krate |
DepNode::Hir(_) |
DepNode::HirBody(_) => {
match dep_node.kind {
DepKind::Krate |
DepKind::Hir |
DepKind::HirBody => {
// HIR nodes are inputs, so if we are asserting that the HIR node is
// dirty, we check the dirty input set.
if !self.dirty_inputs.contains(&dep_node) {
let dep_node_str = self.dep_node_str(&dep_node);
self.tcx.sess.span_err(
item_span,
&format!("`{:?}` not found in dirty set, but should be dirty",
&format!("`{}` not found in dirty set, but should be dirty",
dep_node_str));
}
}
@ -152,25 +155,25 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
let dep_node_str = self.dep_node_str(&dep_node);
self.tcx.sess.span_err(
item_span,
&format!("`{:?}` found in dep graph, but should be dirty", dep_node_str));
&format!("`{}` found in dep graph, but should be dirty", dep_node_str));
}
}
}
}
fn assert_clean(&self, item_span: Span, dep_node: DepNode<DefId>) {
fn assert_clean(&self, item_span: Span, dep_node: DepNode) {
debug!("assert_clean({:?})", dep_node);
match dep_node {
DepNode::Krate |
DepNode::Hir(_) |
DepNode::HirBody(_) => {
match dep_node.kind {
DepKind::Krate |
DepKind::Hir |
DepKind::HirBody => {
// For HIR nodes, check the inputs.
if self.dirty_inputs.contains(&dep_node) {
let dep_node_str = self.dep_node_str(&dep_node);
self.tcx.sess.span_err(
item_span,
&format!("`{:?}` found in dirty-node set, but should be clean",
&format!("`{}` found in dirty-node set, but should be clean",
dep_node_str));
}
}
@ -180,7 +183,7 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
let dep_node_str = self.dep_node_str(&dep_node);
self.tcx.sess.span_err(
item_span,
&format!("`{:?}` not found in dep graph, but should be clean",
&format!("`{}` not found in dep graph, but should be clean",
dep_node_str));
}
}

View file

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use rustc::dep_graph::DepNode;
use rustc::dep_graph::{DepNode, DepKind};
use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
use rustc::hir::svh::Svh;
use rustc::ich::Fingerprint;
@ -45,31 +45,29 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> {
}
}
pub fn is_hashable(dep_node: &DepNode<DefId>) -> bool {
match *dep_node {
DepNode::Krate |
DepNode::Hir(_) |
DepNode::HirBody(_) =>
pub fn is_hashable(tcx: TyCtxt, dep_node: &DepNode) -> bool {
match dep_node.kind {
DepKind::Krate |
DepKind::Hir |
DepKind::HirBody =>
true,
DepNode::MetaData(def_id) => !def_id.is_local(),
DepKind::MetaData => {
let def_id = dep_node.extract_def_id(tcx).unwrap();
!def_id.is_local()
}
_ => false,
}
}
pub fn hash(&mut self, dep_node: &DepNode<DefId>) -> Option<Fingerprint> {
match *dep_node {
DepNode::Krate => {
pub fn hash(&mut self, dep_node: &DepNode) -> Option<Fingerprint> {
match dep_node.kind {
DepKind::Krate => {
Some(self.incremental_hashes_map[dep_node])
}
// HIR nodes (which always come from our crate) are an input:
DepNode::Hir(def_id) |
DepNode::HirBody(def_id) => {
assert!(def_id.is_local(),
"cannot hash HIR for non-local def-id {:?} => {:?}",
def_id,
self.tcx.item_path_str(def_id));
DepKind::Hir |
DepKind::HirBody => {
Some(self.incremental_hashes_map[dep_node])
}
@ -77,10 +75,15 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> {
// MetaData nodes from *our* crates are an *output*; we
// don't hash them, but we do compute a hash for them and
// save it for others to use.
DepNode::MetaData(def_id) if !def_id.is_local() => {
Some(self.metadata_hash(def_id,
DepKind::MetaData => {
let def_id = dep_node.extract_def_id(self.tcx).unwrap();
if !def_id.is_local() {
Some(self.metadata_hash(def_id,
def_id.krate,
|this| &mut this.metadata_hashes))
} else {
None
}
}
_ => {

View file

@ -10,9 +10,8 @@
//! Code to save/load the dep-graph from files.
use rustc::dep_graph::{DepNode, WorkProductId};
use rustc::dep_graph::{DepNode, WorkProductId, DepKind};
use rustc::hir::def_id::DefId;
use rustc::hir::map::DefPathHash;
use rustc::hir::svh::Svh;
use rustc::ich::Fingerprint;
use rustc::session::Session;
@ -33,7 +32,7 @@ use super::work_product;
// The key is a dirty node. The value is **some** base-input that we
// can blame it on.
pub type DirtyNodes = FxHashMap<DepNode<DefPathHash>, DepNode<DefPathHash>>;
pub type DirtyNodes = FxHashMap<DepNode, DepNode>;
/// If we are in incremental mode, and a previous dep-graph exists,
/// then load up those nodes/edges that are still valid into the
@ -118,14 +117,20 @@ fn load_data(sess: &Session, path: &Path) -> Option<Vec<u8>> {
None
}
/// Try to convert a DepNode from the old dep-graph into a DepNode in the
/// current graph by mapping the DefPathHash to a valid DefId. This will fail
/// if the DefPathHash refers to something that has been removed (because
/// there is no DefId for that thing anymore).
fn retrace(tcx: TyCtxt, dep_node: &DepNode<DefPathHash>) -> Option<DepNode<DefId>> {
dep_node.map_def(|def_path_hash| {
tcx.def_path_hash_to_def_id.as_ref().unwrap().get(def_path_hash).cloned()
})
/// Check if a DepNode from the previous dep-graph refers to something that
/// still exists in the current compilation session. Only works for DepNode
/// variants that represent inputs (HIR and imported Metadata).
fn does_still_exist(tcx: TyCtxt, dep_node: &DepNode) -> bool {
match dep_node.kind {
DepKind::Hir |
DepKind::HirBody |
DepKind::MetaData => {
dep_node.extract_def_id(tcx).is_some()
}
_ => {
bug!("unexpected Input DepNode: {:?}", dep_node)
}
}
}
/// Decode the dep graph and load the edges/nodes that are still clean
@ -161,7 +166,7 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let serialized_dep_graph = SerializedDepGraph::decode(&mut dep_graph_decoder)?;
let edge_map: FxHashMap<DepNode<DefPathHash>, Vec<DepNode<DefPathHash>>> = {
let edge_map: FxHashMap<DepNode, Vec<DepNode>> = {
let capacity = serialized_dep_graph.edge_list_data.len();
let mut edge_map = FxHashMap::with_capacity_and_hasher(capacity, Default::default());
@ -194,46 +199,26 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// Recreate the edges in the graph that are still clean.
let mut clean_work_products = FxHashSet();
let mut dirty_work_products = FxHashSet(); // incomplete; just used to suppress debug output
let mut extra_edges = vec![];
for (source, targets) in &edge_map {
for target in targets {
process_edges(tcx, source, target, &edge_map, &dirty_raw_nodes,
&mut clean_work_products, &mut dirty_work_products, &mut extra_edges);
process_edge(tcx, source, target, &dirty_raw_nodes,
&mut clean_work_products, &mut dirty_work_products);
}
}
// Recreate bootstrap outputs, which are outputs that have no incoming edges (and hence cannot
// be dirty).
for bootstrap_output in &serialized_dep_graph.bootstrap_outputs {
if let Some(n) = retrace(tcx, bootstrap_output) {
if let DepNode::WorkProduct(ref wp) = n {
clean_work_products.insert(wp.clone());
}
tcx.dep_graph.with_task(n, (), (), create_node);
fn create_node((): (), (): ()) {
// just create the node with no inputs
}
if let DepKind::WorkProduct = bootstrap_output.kind {
let wp_id = WorkProductId::from_fingerprint(bootstrap_output.hash);
clean_work_products.insert(wp_id);
}
}
// Subtle. Sometimes we have intermediate nodes that we can't recreate in the new graph.
// This is pretty unusual but it arises in a scenario like this:
//
// Hir(X) -> Foo(Y) -> Bar
//
// Note that the `Hir(Y)` is not an input to `Foo(Y)` -- this
// almost never happens, but can happen in some obscure
// scenarios. In that case, if `Y` is removed, then we can't
// recreate `Foo(Y)` (the def-id `Y` no longer exists); what we do
// then is to push the edge `Hir(X) -> Bar` onto `extra_edges`
// (along with any other targets of `Foo(Y)`). We will then add
// the edge from `Hir(X)` to `Bar` (or, if `Bar` itself cannot be
// recreated, to the targets of `Bar`).
while let Some((source, target)) = extra_edges.pop() {
process_edges(tcx, source, target, &edge_map, &dirty_raw_nodes,
&mut clean_work_products, &mut dirty_work_products, &mut extra_edges);
tcx.dep_graph.with_task(*bootstrap_output, (), (), create_node);
fn create_node((): (), (): ()) {
// just create the node with no inputs
}
}
// Add in work-products that are still clean, and delete those that are
@ -256,40 +241,37 @@ fn initial_dirty_nodes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let mut hcx = HashContext::new(tcx, incremental_hashes_map);
let mut dirty_nodes = FxHashMap();
let print_removed_message = |dep_node: &DepNode<_>| {
if tcx.sess.opts.debugging_opts.incremental_dump_hash {
println!("node {:?} is dirty as it was removed", dep_node);
}
debug!("initial_dirty_nodes: {:?} is dirty as it was removed", dep_node);
};
for hash in serialized_hashes {
if let Some(dep_node) = retrace(tcx, &hash.dep_node) {
if let Some(current_hash) = hcx.hash(&dep_node) {
if current_hash == hash.hash {
debug!("initial_dirty_nodes: {:?} is clean (hash={:?})",
dep_node.map_def(|&def_id| Some(tcx.def_path(def_id))).unwrap(),
let dep_node = hash.dep_node;
if does_still_exist(tcx, &dep_node) {
let current_hash = hcx.hash(&dep_node).unwrap_or_else(|| {
bug!("Cannot find current ICH for input that still exists?")
});
if current_hash == hash.hash {
debug!("initial_dirty_nodes: {:?} is clean (hash={:?})",
dep_node,
current_hash);
continue;
}
if tcx.sess.opts.debugging_opts.incremental_dump_hash {
println!("node {:?} is dirty as hash is {:?} was {:?}",
dep_node.map_def(|&def_id| Some(tcx.def_path(def_id))).unwrap(),
current_hash,
hash.hash);
}
debug!("initial_dirty_nodes: {:?} is dirty as hash is {:?}, was {:?}",
dep_node.map_def(|&def_id| Some(tcx.def_path(def_id))).unwrap(),
current_hash,
hash.hash);
} else {
print_removed_message(&hash.dep_node);
continue;
}
if tcx.sess.opts.debugging_opts.incremental_dump_hash {
println!("node {:?} is dirty as hash is {:?}, was {:?}",
dep_node,
current_hash,
hash.hash);
}
debug!("initial_dirty_nodes: {:?} is dirty as hash is {:?}, was {:?}",
dep_node,
current_hash,
hash.hash);
} else {
print_removed_message(&hash.dep_node);
if tcx.sess.opts.debugging_opts.incremental_dump_hash {
println!("node {:?} is dirty as it was removed", dep_node);
}
debug!("initial_dirty_nodes: {:?} is dirty as it was removed", dep_node);
}
dirty_nodes.insert(hash.dep_node.clone(), hash.dep_node.clone());
@ -298,11 +280,11 @@ fn initial_dirty_nodes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
dirty_nodes
}
fn transitive_dirty_nodes(edge_map: &FxHashMap<DepNode<DefPathHash>, Vec<DepNode<DefPathHash>>>,
fn transitive_dirty_nodes(edge_map: &FxHashMap<DepNode, Vec<DepNode>>,
mut dirty_nodes: DirtyNodes)
-> DirtyNodes
{
let mut stack: Vec<(DepNode<DefPathHash>, DepNode<DefPathHash>)> = vec![];
let mut stack: Vec<(DepNode, DepNode)> = vec![];
stack.extend(dirty_nodes.iter().map(|(s, b)| (s.clone(), b.clone())));
while let Some((source, blame)) = stack.pop() {
// we know the source is dirty (because of the node `blame`)...
@ -366,6 +348,7 @@ fn delete_dirty_work_product(tcx: TyCtxt,
fn load_prev_metadata_hashes(tcx: TyCtxt,
output: &mut FxHashMap<DefId, Fingerprint>) {
if !tcx.sess.opts.debugging_opts.query_dep_graph {
// Previous metadata hashes are only needed for testing.
return
}
@ -417,71 +400,70 @@ fn load_prev_metadata_hashes(tcx: TyCtxt,
serialized_hashes.index_map.len());
}
fn process_edges<'a, 'tcx, 'edges>(
fn process_edge<'a, 'tcx, 'edges>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
source: &'edges DepNode<DefPathHash>,
target: &'edges DepNode<DefPathHash>,
edges: &'edges FxHashMap<DepNode<DefPathHash>, Vec<DepNode<DefPathHash>>>,
source: &'edges DepNode,
target: &'edges DepNode,
dirty_raw_nodes: &DirtyNodes,
clean_work_products: &mut FxHashSet<WorkProductId>,
dirty_work_products: &mut FxHashSet<WorkProductId>,
extra_edges: &mut Vec<(&'edges DepNode<DefPathHash>, &'edges DepNode<DefPathHash>)>)
dirty_work_products: &mut FxHashSet<WorkProductId>)
{
// If the target is dirty, skip the edge. If this is an edge
// that targets a work-product, we can print the blame
// information now.
if let Some(blame) = dirty_raw_nodes.get(target) {
if let DepNode::WorkProduct(ref wp) = *target {
if let DepKind::WorkProduct = target.kind {
if tcx.sess.opts.debugging_opts.incremental_info {
if dirty_work_products.insert(wp.clone()) {
let wp_id = WorkProductId::from_fingerprint(target.hash);
if dirty_work_products.insert(wp_id) {
// Try to reconstruct the human-readable version of the
// DepNode. This cannot be done for things that where
// removed.
let readable_blame = if let Some(dep_node) = retrace(tcx, blame) {
dep_node.map_def(|&def_id| Some(tcx.def_path(def_id).to_string(tcx)))
.unwrap()
let blame_str = if let Some(def_id) = blame.extract_def_id(tcx) {
format!("{:?}({})",
blame.kind,
tcx.def_path(def_id).to_string(tcx))
} else {
blame.map_def(|def_path_hash| Some(format!("{:?}", def_path_hash)))
.unwrap()
format!("{:?}", blame)
};
println!("incremental: module {:?} is dirty because {:?} \
changed or was removed",
wp,
readable_blame);
wp_id,
blame_str);
}
}
}
return;
}
// If the source is dirty, the target will be dirty.
assert!(!dirty_raw_nodes.contains_key(source));
// At this point we have asserted that the target is clean -- otherwise, we
// would have hit the return above. We can do some further consistency
// checks based on this fact:
// Retrace the source -> target edges to def-ids and then create
// an edge in the graph. Retracing may yield none if some of the
// data happens to have been removed.
if let Some(source_node) = retrace(tcx, source) {
if let Some(target_node) = retrace(tcx, target) {
let _task = tcx.dep_graph.in_task(target_node);
tcx.dep_graph.read(source_node);
if let DepNode::WorkProduct(ref wp) = *target {
clean_work_products.insert(wp.clone());
}
} else {
// As discussed in `decode_dep_graph` above, sometimes the
// target cannot be recreated again, in which case we add
// edges to go from `source` to the targets of `target`.
extra_edges.extend(
edges[target].iter().map(|t| (source, t)));
// We should never have an edge where the target is clean but the source
// was dirty. Otherwise something was wrong with the dirtying pass above:
debug_assert!(!dirty_raw_nodes.contains_key(source));
// We also never should encounter an edge going from a removed input to a
// clean target because removing the input would have dirtied the input
// node and transitively dirtied the target.
debug_assert!(match source.kind {
DepKind::Hir | DepKind::HirBody | DepKind::MetaData => {
does_still_exist(tcx, source)
}
_ => true,
});
if !dirty_raw_nodes.contains_key(target) {
let _task = tcx.dep_graph.in_task(*target);
tcx.dep_graph.read(*source);
if let DepKind::WorkProduct = target.kind {
let wp_id = WorkProductId::from_fingerprint(target.hash);
clean_work_products.insert(wp_id);
}
} else {
// It's also possible that the source can't be created! But we
// can ignore such cases, because (a) if `source` is a HIR
// node, it would be considered dirty; and (b) in other cases,
// there must be some input to this node that is clean, and so
// we'll re-create the edges over in the case where target is
// undefined.
}
}

View file

@ -8,8 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use rustc::dep_graph::{DepGraphQuery, DepNode};
use rustc::hir::def_id::DefId;
use rustc::dep_graph::{DepGraphQuery, DepNode, DepKind};
use rustc::ich::Fingerprint;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::graph::{Graph, NodeIndex};
@ -26,7 +25,7 @@ pub struct Predecessors<'query> {
// nodes) and all of the "work-products" we may care about
// later. Other nodes may be retained if it keeps the overall size
// of the graph down.
pub reduced_graph: Graph<&'query DepNode<DefId>, ()>,
pub reduced_graph: Graph<&'query DepNode, ()>,
// These are output nodes that have no incoming edges. We have to
// track these specially because, when we load the data back up
@ -34,32 +33,32 @@ pub struct Predecessors<'query> {
// to recreate the nodes where all incoming edges are clean; but
// since we ordinarily just serialize edges, we wind up just
// forgetting that bootstrap outputs even exist in that case.)
pub bootstrap_outputs: Vec<&'query DepNode<DefId>>,
pub bootstrap_outputs: Vec<&'query DepNode>,
// For the inputs (hir/foreign-metadata), we include hashes.
pub hashes: FxHashMap<&'query DepNode<DefId>, Fingerprint>,
pub hashes: FxHashMap<&'query DepNode, Fingerprint>,
}
impl<'q> Predecessors<'q> {
pub fn new(query: &'q DepGraphQuery<DefId>, hcx: &mut HashContext) -> Self {
pub fn new(query: &'q DepGraphQuery, hcx: &mut HashContext) -> Self {
let tcx = hcx.tcx;
// Find the set of "start nodes". These are nodes that we will
// possibly query later.
let is_output = |node: &DepNode<DefId>| -> bool {
match *node {
DepNode::WorkProduct(_) => true,
DepNode::MetaData(ref def_id) => {
let is_output = |node: &DepNode| -> bool {
match node.kind {
DepKind::WorkProduct => true,
DepKind::MetaData => {
// We do *not* create dep-nodes for the current crate's
// metadata anymore, just for metadata that we import/read
// from other crates.
debug_assert!(!def_id.is_local());
debug_assert!(!node.extract_def_id(tcx).unwrap().is_local());
false
}
// if -Z query-dep-graph is passed, save more extended data
// to enable better unit testing
DepNode::TypeckTables(_) |
DepNode::TransCrateItem(_) => tcx.sess.opts.debugging_opts.query_dep_graph,
DepKind::TypeckTables |
DepKind::TransCrateItem => tcx.sess.opts.debugging_opts.query_dep_graph,
_ => false,
}
@ -67,7 +66,9 @@ impl<'q> Predecessors<'q> {
// Reduce the graph to the most important nodes.
let compress::Reduction { graph, input_nodes } =
compress::reduce_graph(&query.graph, HashContext::is_hashable, |n| is_output(n));
compress::reduce_graph(&query.graph,
|n| HashContext::is_hashable(tcx, n),
|n| is_output(n));
let mut hashes = FxHashMap();
for input_index in input_nodes {
@ -81,8 +82,8 @@ impl<'q> Predecessors<'q> {
// Not all inputs might have been reachable from an output node,
// but we still want their hash for our unit tests.
let hir_nodes = query.graph.all_nodes().iter().filter_map(|node| {
match node.data {
DepNode::Hir(_) => Some(&node.data),
match node.data.kind {
DepKind::Hir => Some(&node.data),
_ => None,
}
});
@ -93,7 +94,7 @@ impl<'q> Predecessors<'q> {
}
}
let bootstrap_outputs: Vec<&'q DepNode<DefId>> =
let bootstrap_outputs: Vec<&'q DepNode> =
(0 .. graph.len_nodes())
.map(NodeIndex)
.filter(|&n| graph.incoming_edges(n).next().is_none())

View file

@ -11,7 +11,6 @@
use rustc::dep_graph::DepNode;
use rustc::hir::def_id::DefId;
use rustc::hir::svh::Svh;
use rustc::hir::map::DefPathHash;
use rustc::ich::Fingerprint;
use rustc::middle::cstore::EncodedMetadataHashes;
use rustc::session::Session;
@ -174,16 +173,12 @@ pub fn encode_dep_graph(tcx: TyCtxt,
// First encode the commandline arguments hash
tcx.sess.opts.dep_tracking_hash().encode(encoder)?;
let to_hash_based_node = |dep_node: &DepNode<DefId>| {
dep_node.map_def(|&def_id| Some(tcx.def_path_hash(def_id))).unwrap()
};
// NB: We rely on this Vec being indexable by reduced_graph's NodeIndex.
let nodes: IndexVec<DepNodeIndex, DepNode<DefPathHash>> = preds
let nodes: IndexVec<DepNodeIndex, DepNode> = preds
.reduced_graph
.all_nodes()
.iter()
.map(|node| to_hash_based_node(node.data))
.map(|node| node.data.clone())
.collect();
let mut edge_list_indices = Vec::with_capacity(nodes.len());
@ -206,18 +201,17 @@ pub fn encode_dep_graph(tcx: TyCtxt,
// Check that we have a consistent number of edges.
assert_eq!(edge_list_data.len(), preds.reduced_graph.len_edges());
let bootstrap_outputs = preds
.bootstrap_outputs
.iter()
.map(|n| to_hash_based_node(n))
.collect();
let bootstrap_outputs = preds.bootstrap_outputs
.iter()
.map(|dep_node| (**dep_node).clone())
.collect();
let hashes = preds
.hashes
.iter()
.map(|(&dep_node, &hash)| {
SerializedHash {
dep_node: to_hash_based_node(dep_node),
dep_node: dep_node.clone(),
hash: hash,
}
})

View file

@ -255,6 +255,13 @@ impl CStore {
pub fn do_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option<CrateNum> {
self.extern_mod_crate_map.borrow().get(&emod_id).cloned()
}
pub fn read_dep_node(&self, def_id: DefId) {
use rustc::middle::cstore::CrateStore;
let def_path_hash = self.def_path_hash(def_id);
let dep_node = def_path_hash.to_dep_node(::rustc::dep_graph::DepKind::MetaData);
self.dep_graph.read(dep_node);
}
}
impl CrateMetadata {

View file

@ -22,8 +22,6 @@ use rustc::session::Session;
use rustc::ty::{self, TyCtxt};
use rustc::ty::maps::Providers;
use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc::dep_graph::{DepNode};
use rustc::hir::map::{DefKey, DefPath, DisambiguatedDefPathData, DefPathHash};
use rustc::hir::map::definitions::{DefPathTable, GlobalMetaDataKind};
use rustc::util::nodemap::{NodeSet, DefIdMap};
@ -48,7 +46,10 @@ macro_rules! provide {
DepTrackingMapConfig>::Value {
assert!(!$def_id.is_local());
$tcx.dep_graph.read(DepNode::MetaData($def_id));
let def_path_hash = $tcx.def_path_hash($def_id);
let dep_node = def_path_hash.to_dep_node(::rustc::dep_graph::DepKind::MetaData);
$tcx.dep_graph.read(dep_node);
let $cdata = $tcx.sess.cstore.crate_data_as_rc_any($def_id.krate);
let $cdata = $cdata.downcast_ref::<cstore::CrateMetadata>()
@ -140,12 +141,12 @@ impl CrateStore for cstore::CStore {
}
fn visibility(&self, def: DefId) -> ty::Visibility {
self.dep_graph.read(DepNode::MetaData(def));
self.read_dep_node(def);
self.get_crate_data(def.krate).get_visibility(def.index)
}
fn item_generics_cloned(&self, def: DefId) -> ty::Generics {
self.dep_graph.read(DepNode::MetaData(def));
self.read_dep_node(def);
self.get_crate_data(def.krate).get_generics(def.index)
}
@ -161,19 +162,19 @@ impl CrateStore for cstore::CStore {
fn impl_defaultness(&self, def: DefId) -> hir::Defaultness
{
self.dep_graph.read(DepNode::MetaData(def));
self.read_dep_node(def);
self.get_crate_data(def.krate).get_impl_defaultness(def.index)
}
fn associated_item_cloned(&self, def: DefId) -> ty::AssociatedItem
{
self.dep_graph.read(DepNode::MetaData(def));
self.read_dep_node(def);
self.get_crate_data(def.krate).get_associated_item(def.index)
}
fn is_const_fn(&self, did: DefId) -> bool
{
self.dep_graph.read(DepNode::MetaData(did));
self.read_dep_node(did);
self.get_crate_data(did.krate).is_const_fn(did.index)
}
@ -344,13 +345,13 @@ impl CrateStore for cstore::CStore {
fn struct_field_names(&self, def: DefId) -> Vec<ast::Name>
{
self.dep_graph.read(DepNode::MetaData(def));
self.read_dep_node(def);
self.get_crate_data(def.krate).get_struct_field_names(def.index)
}
fn item_children(&self, def_id: DefId) -> Vec<def::Export>
{
self.dep_graph.read(DepNode::MetaData(def_id));
self.read_dep_node(def_id);
let mut result = vec![];
self.get_crate_data(def_id.krate)
.each_child_of_item(def_id.index, |child| result.push(child));
@ -398,11 +399,12 @@ impl CrateStore for cstore::CStore {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId)
-> &'tcx hir::Body {
if let Some(cached) = tcx.hir.get_inlined_body(def_id) {
self.read_dep_node(def_id);
if let Some(cached) = tcx.hir.get_inlined_body_untracked(def_id) {
return cached;
}
self.dep_graph.read(DepNode::MetaData(def_id));
debug!("item_body({:?}): inlining item", def_id);
self.get_crate_data(def_id.krate).item_body(tcx, def_id.index)

View file

@ -13,7 +13,7 @@
use cstore::{self, CrateMetadata, MetadataBlob, NativeLibrary};
use schema::*;
use rustc::dep_graph::{DepGraph, DepNode};
use rustc::dep_graph::{DepGraph, DepNode, DepKind};
use rustc::hir::map::{DefKey, DefPath, DefPathData, DefPathHash};
use rustc::hir::map::definitions::GlobalMetaDataKind;
use rustc::hir;
@ -876,7 +876,8 @@ impl<'a, 'tcx> CrateMetadata {
return Rc::new([]);
}
dep_graph.read(DepNode::MetaData(self.local_def_id(node_id)));
let dep_node = self.def_path_hash(node_id).to_dep_node(DepKind::MetaData);
dep_graph.read(dep_node);
if let Some(&Some(ref val)) =
self.attribute_cache.borrow()[node_as].get(node_index) {
@ -1194,8 +1195,9 @@ impl<'a, 'tcx> CrateMetadata {
self.codemap_import_info.borrow()
}
pub fn metadata_dep_node(&self, kind: GlobalMetaDataKind) -> DepNode<DefId> {
pub fn metadata_dep_node(&self, kind: GlobalMetaDataKind) -> DepNode {
let def_index = kind.def_index(&self.def_path_table);
DepNode::MetaData(self.local_def_id(def_index))
let def_path_hash = self.def_path_table.def_path_hash(def_index);
def_path_hash.to_dep_node(DepKind::MetaData)
}
}

View file

@ -203,7 +203,7 @@ impl<T> Tracked<T> {
}
}
pub fn get(&self, dep_graph: &DepGraph, dep_node: DepNode<DefId>) -> &T {
pub fn get(&self, dep_graph: &DepGraph, dep_node: DepNode) -> &T {
dep_graph.read(dep_node);
&self.state
}

View file

@ -23,7 +23,7 @@ use rustc::middle::dependency_format::Linkage;
use CrateTranslation;
use rustc::util::common::time;
use rustc::util::fs::fix_windows_verbatim_for_gcc;
use rustc::dep_graph::DepNode;
use rustc::dep_graph::{DepKind, DepNode};
use rustc::hir::def_id::CrateNum;
use rustc::hir::svh::Svh;
use rustc_back::tempdir::TempDir;
@ -134,8 +134,9 @@ pub fn find_crate_name(sess: Option<&Session>,
}
pub fn build_link_meta(incremental_hashes_map: &IncrementalHashesMap) -> LinkMeta {
let krate_dep_node = &DepNode::new_no_params(DepKind::Krate);
let r = LinkMeta {
crate_hash: Svh::new(incremental_hashes_map[&DepNode::Krate].to_smaller_hash()),
crate_hash: Svh::new(incremental_hashes_map[krate_dep_node].to_smaller_hash()),
};
info!("{:?}", r);
return r;

View file

@ -167,8 +167,8 @@ impl<'tcx> CodegenUnit<'tcx> {
WorkProductId::from_cgu_name(self.name())
}
pub fn work_product_dep_node(&self) -> DepNode<DefId> {
DepNode::WorkProduct(self.work_product_id())
pub fn work_product_dep_node(&self) -> DepNode {
self.work_product_id().to_dep_node()
}
pub fn compute_symbol_name_hash<'a>(&self,

View file

@ -23,7 +23,7 @@ use common;
use declare;
use llvm;
use monomorphize::Instance;
use rustc::dep_graph::DepNode;
use rustc::dep_graph::DepKind;
use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
@ -75,14 +75,16 @@ impl<'a, 'tcx> TransItem<'tcx> {
match *self {
TransItem::Static(node_id) => {
let def_id = ccx.tcx().hir.local_def_id(node_id);
let _task = ccx.tcx().dep_graph.in_task(DepNode::TransCrateItem(def_id)); // (*)
let item = ccx.tcx().hir.expect_item(node_id);
let tcx = ccx.tcx();
let def_id = tcx.hir.local_def_id(node_id);
let dep_node = def_id.to_dep_node(tcx, DepKind::TransCrateItem);
let _task = ccx.tcx().dep_graph.in_task(dep_node); // (*)
let item = tcx.hir.expect_item(node_id);
if let hir::ItemStatic(_, m, _) = item.node {
match consts::trans_static(&ccx, m, item.id, &item.attrs) {
Ok(_) => { /* Cool, everything's alright. */ },
Err(err) => {
err.report(ccx.tcx(), item.span, "static");
err.report(tcx, item.span, "static");
}
};
} else {
@ -99,7 +101,8 @@ impl<'a, 'tcx> TransItem<'tcx> {
}
TransItem::Fn(instance) => {
let _task = ccx.tcx().dep_graph.in_task(
DepNode::TransCrateItem(instance.def_id())); // (*)
instance.def_id()
.to_dep_node(ccx.tcx(), DepKind::TransCrateItem)); // (*)
base::trans_instance(&ccx, instance);
}

View file

@ -17,7 +17,7 @@
//! `tcx.inherent_impls(def_id)`). That value, however,
//! is computed by selecting an idea from this table.
use rustc::dep_graph::DepNode;
use rustc::dep_graph::DepKind;
use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
use rustc::hir;
use rustc::hir::itemlikevisit::ItemLikeVisitor;
@ -79,7 +79,8 @@ pub fn inherent_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
});
for &impl_def_id in &result[..] {
tcx.dep_graph.read(DepNode::Hir(impl_def_id));
let def_path_hash = tcx.def_path_hash(impl_def_id);
tcx.dep_graph.read(def_path_hash.to_dep_node(DepKind::Hir));
}
result

View file

@ -15,7 +15,7 @@
use rustc::traits;
use rustc::ty::{self, TyCtxt, TypeFoldable};
use syntax::ast;
use rustc::dep_graph::DepNode;
use rustc::dep_graph::DepKind;
use rustc::hir;
use rustc::hir::itemlikevisit::ItemLikeVisitor;
@ -39,7 +39,8 @@ pub fn check_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, node_id: ast::NodeId) {
}
let _task =
tcx.dep_graph.in_task(DepNode::CoherenceOverlapCheck(trait_def_id));
tcx.dep_graph.in_task(trait_def_id.to_dep_node(tcx,
DepKind::CoherenceOverlapCheck));
// Trigger building the specialization graph for the trait of this impl.
// This will detect any overlap errors.

View file

@ -15,7 +15,7 @@
use hir::def_id::DefId;
use middle::resolve_lifetime as rl;
use rustc::dep_graph::{AssertDepGraphSafe, DepNode};
use rustc::dep_graph::{AssertDepGraphSafe, DepKind};
use rustc::ty::subst::Substs;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::hir::map as hir_map;
@ -104,7 +104,8 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> {
hir::ItemEnum(..) |
hir::ItemStruct(..) |
hir::ItemUnion(..) => {
tcx.dep_graph.with_task(DepNode::ItemVarianceConstraints(def_id),
let dep_node = def_id.to_dep_node(tcx, DepKind::ItemVarianceConstraints);
tcx.dep_graph.with_task(dep_node,
AssertDepGraphSafe(self),
def_id,
visit_item_task);

View file

@ -12,7 +12,7 @@
//! parameters. See README.md for details.
use arena;
use rustc::dep_graph::DepNode;
use rustc::dep_graph::DepKind;
use rustc::hir;
use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
use rustc::ty::{self, CrateVariancesMap, TyCtxt};
@ -72,12 +72,15 @@ fn variances_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_def_id: DefId)
// Lacking red/green, we read the variances for all items here
// but ignore the dependencies, then re-synthesize the ones we need.
let crate_map = tcx.dep_graph.with_ignore(|| tcx.crate_variances(LOCAL_CRATE));
tcx.dep_graph.read(DepNode::ItemVarianceConstraints(item_def_id));
let dep_node = item_def_id.to_dep_node(tcx, DepKind::ItemVarianceConstraints);
tcx.dep_graph.read(dep_node);
for &dep_def_id in crate_map.dependencies.less_than(&item_def_id) {
if dep_def_id.is_local() {
tcx.dep_graph.read(DepNode::ItemVarianceConstraints(dep_def_id));
let dep_node = dep_def_id.to_dep_node(tcx, DepKind::ItemVarianceConstraints);
tcx.dep_graph.read(dep_node);
} else {
tcx.dep_graph.read(DepNode::ItemVariances(dep_def_id));
let dep_node = dep_def_id.to_dep_node(tcx, DepKind::ItemVariances);
tcx.dep_graph.read(dep_node);
}
}

View file

@ -38,8 +38,8 @@ mod y {
#[rustc_clean(label="TypeckTables", cfg="cfail2")]
#[rustc_clean(label="TransCrateItem", cfg="cfail2")]
pub fn y() {
//[cfail2]~^ ERROR `TypeckTables("y::y")` not found in dep graph, but should be clean
//[cfail2]~| ERROR `TransCrateItem("y::y")` not found in dep graph, but should be clean
//[cfail2]~^ ERROR `TypeckTables(y::y)` not found in dep graph, but should be clean
//[cfail2]~| ERROR `TransCrateItem(y::y)` not found in dep graph, but should be clean
x::x();
}
}
@ -48,7 +48,7 @@ mod z {
#[rustc_dirty(label="TypeckTables", cfg="cfail2")]
#[rustc_dirty(label="TransCrateItem", cfg="cfail2")]
pub fn z() {
//[cfail2]~^ ERROR `TypeckTables("z::z")` found in dep graph, but should be dirty
//[cfail2]~| ERROR `TransCrateItem("z::z")` found in dep graph, but should be dirty
//[cfail2]~^ ERROR `TypeckTables(z::z)` found in dep graph, but should be dirty
//[cfail2]~| ERROR `TransCrateItem(z::z)` found in dep graph, but should be dirty
}
}