From 36071749092b03ba454aa16eaf68dd5341d69619 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 2 Jun 2017 17:36:30 +0200 Subject: [PATCH 1/3] incr.comp.: Uniformly represent DepNodes as (Kind, StableHash) pairs. --- src/librustc/dep_graph/debug.rs | 11 +- src/librustc/dep_graph/dep_node.rs | 625 +++++++++++------- src/librustc/dep_graph/dep_tracking_map.rs | 33 +- src/librustc/dep_graph/edges.rs | 26 +- src/librustc/dep_graph/graph.rs | 9 +- src/librustc/dep_graph/mod.rs | 2 + src/librustc/dep_graph/query.rs | 30 +- src/librustc/dep_graph/raii.rs | 5 +- src/librustc/dep_graph/shadow.rs | 11 +- src/librustc/dep_graph/thread.rs | 15 +- src/librustc/hir/map/mod.rs | 45 +- src/librustc/lint/context.rs | 4 +- src/librustc/traits/fulfill.rs | 15 +- src/librustc/traits/select.rs | 6 +- src/librustc/traits/trans/mod.rs | 15 +- src/librustc/ty/instance.rs | 7 +- src/librustc/ty/maps.rs | 79 ++- src/librustc/ty/mod.rs | 12 +- src/librustc/util/common.rs | 6 +- src/librustc_incremental/assert_dep_graph.rs | 71 +- src/librustc_incremental/calculate_svh/mod.rs | 84 ++- src/librustc_incremental/persist/data.rs | 6 +- .../persist/dirty_clean.rs | 61 +- src/librustc_incremental/persist/hash.rs | 41 +- src/librustc_incremental/persist/load.rs | 208 +++--- src/librustc_incremental/persist/preds/mod.rs | 35 +- src/librustc_incremental/persist/save.rs | 20 +- src/librustc_metadata/cstore.rs | 7 + src/librustc_metadata/cstore_impl.rs | 26 +- src/librustc_metadata/decoder.rs | 10 +- src/librustc_metadata/schema.rs | 2 +- src/librustc_trans/back/link.rs | 5 +- src/librustc_trans/partitioning.rs | 4 +- src/librustc_trans/trans_item.rs | 15 +- .../coherence/inherent_impls.rs | 5 +- src/librustc_typeck/coherence/overlap.rs | 5 +- src/librustc_typeck/variance/constraints.rs | 5 +- src/librustc_typeck/variance/mod.rs | 11 +- src/test/incremental/dirty_clean.rs | 8 +- 39 files changed, 864 insertions(+), 721 deletions(-) diff --git a/src/librustc/dep_graph/debug.rs b/src/librustc/dep_graph/debug.rs index 5b15c5e67174e..e22552008d5a8 100644 --- a/src/librustc/dep_graph/debug.rs +++ b/src/librustc/dep_graph/debug.rs @@ -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(&self, node: &DepNode) -> 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(&self, - source: &DepNode, - target: &DepNode) - -> bool { + pub fn test(&self, + source: &DepNode, + target: &DepNode) + -> bool { self.source.test(source) && self.target.test(target) } } diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 1571cf344ede1..5f3dd9052034f 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -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) => ({}) +} + +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),* + } + + 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 { + 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 { + 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) + } } -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] -pub enum DepNode { - // The `D` type is "how definitions are identified". - // During compilation, it is always `DefId`, but when serializing - // it is mapped to `DefPath`. - - /// Represents the `Krate` as a whole (the `hir::Krate` value) (as - /// distinct from the krate module). This is basically a hash of - /// the entire krate, so if you read from `Krate` (e.g., by calling - /// `tcx.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 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), + 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 { // 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), - - /// 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), + 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(DefId), AllLocalTraitImpls, @@ -129,184 +330,80 @@ pub enum DepNode { // 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), - - /// Trait selection cache is a little funny. Given a trait - /// reference like `Foo: SomeTrait`, 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: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Vec }` - /// - `String: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: String }` - /// - `Foo: Trait` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }` - /// - `Foo: Trait` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }` - /// - `(Foo, Bar): Trait` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }` - /// - `i32: Trait` -> `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 }, - - /// For proj. cache, we just keep a list of all def-ids, since it is - /// not a hotspot. - ProjectionCache { def_ids: Vec }, - - 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), + TraitItems(DefId), + ReprHints(DefId), + + // Trait selection cache is a little funny. Given a trait + // reference like `Foo: SomeTrait`, 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: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Vec }` + // - `String: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: String }` + // - `Foo: Trait` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }` + // - `Foo: Trait` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }` + // - `(Foo, Bar): Trait` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }` + // - `i32: Trait` -> `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: DefIdList }, + + 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 DepNode { - /// Used in testing - pub fn from_label_string(label: &str, data: D) -> Result, ()> { - macro_rules! check { - ($($name:ident,)*) => { - match label { - $(stringify!($name) => Ok(DepNode::$name(data)),)* - _ => Err(()) - } - } - } +impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a, T> DepNodeParams<'a, 'gcx, 'tcx> for T + where T: HashStable> +{ + 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(&self, mut op: OP) -> Option> - where OP: FnMut(&D) -> Option, E: Clone + Debug - { - use self::DepNode::*; - - 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> = 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> = 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), - } +impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> DepNodeParams<'a, 'gcx, 'tcx> for (DefId,) { + const CAN_RECONSTRUCT_QUERY_KEY: bool = true; + + fn to_fingerprint(&self, tcx: TyCtxt) -> Fingerprint { + tcx.def_path_hash(self.0).0 } } @@ -315,14 +412,38 @@ impl DepNode { /// 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; diff --git a/src/librustc/dep_graph/dep_tracking_map.rs b/src/librustc/dep_graph/dep_tracking_map.rs index 7a246c814d3ec..43f8d6b938dab 100644 --- a/src/librustc/dep_graph/dep_tracking_map.rs +++ b/src/librustc/dep_graph/dep_tracking_map.rs @@ -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 { pub trait DepTrackingMapConfig { type Key: Eq + Hash + Clone; type Value: Clone; - fn to_dep_node(key: &Self::Key) -> DepNode; + fn to_dep_node(tcx: TyCtxt, key: &Self::Key) -> DepNode; } impl DepTrackingMap { @@ -44,18 +43,18 @@ impl DepTrackingMap { /// 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 MemoizationMap for RefCell> { /// 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(&self, key: M::Key, op: OP) -> M::Value + fn memoize(&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 { - type Output = M::Value; - - #[inline] - fn index(&self, k: &'k M::Key) -> &M::Value { - self.get(k).unwrap() - } -} - diff --git a/src/librustc/dep_graph/edges.rs b/src/librustc/dep_graph/edges.rs index 5dbabcc923048..a323e44d0d427 100644 --- a/src/librustc/dep_graph/edges.rs +++ b/src/librustc/dep_graph/edges.rs @@ -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 { - nodes: Vec>, - indices: FxHashMap, IdIndex>, +pub struct DepGraphEdges { + nodes: Vec, + indices: FxHashMap, edges: FxHashSet<(IdIndex, IdIndex)>, open_nodes: Vec, } @@ -42,8 +40,8 @@ enum OpenNode { Ignore, } -impl DepGraphEdges { - pub fn new() -> DepGraphEdges { +impl DepGraphEdges { + pub fn new() -> DepGraphEdges { DepGraphEdges { nodes: vec![], indices: FxHashMap(), @@ -52,12 +50,12 @@ impl DepGraphEdges { } } - fn id(&self, index: IdIndex) -> DepNode { + fn id(&self, index: IdIndex) -> DepNode { self.nodes[index.index()].clone() } /// Creates a node for `id` in the graph. - fn make_node(&mut self, id: DepNode) -> IdIndex { + fn make_node(&mut self, id: DepNode) -> IdIndex { if let Some(&i) = self.indices.get(&id) { return i; } @@ -82,7 +80,7 @@ impl DepGraphEdges { assert_eq!(popped_node, OpenNode::Ignore); } - pub fn push_task(&mut self, key: DepNode) { + pub fn push_task(&mut self, key: DepNode) { let top_node = self.current_node(); let new_node = self.make_node(key); @@ -95,7 +93,7 @@ impl DepGraphEdges { } } - pub fn pop_task(&mut self, key: DepNode) { + pub fn pop_task(&mut self, key: DepNode) { let popped_node = self.open_nodes.pop().unwrap(); assert_eq!(OpenNode::Node(self.indices[&key]), popped_node); } @@ -105,7 +103,7 @@ impl DepGraphEdges { /// 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) { + 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 DepGraphEdges { /// Indicates that the current task `C` writes `v` by adding an /// edge from `C` to `v`. If there is no current task, panics. If /// you want to suppress this edge, use `ignore`. - pub fn write(&mut self, v: DepNode) { + pub fn write(&mut self, v: DepNode) { let target = self.make_node(v); self.add_edge_from_current_node(|current| (current, target)) } @@ -159,7 +157,7 @@ impl DepGraphEdges { } } - pub fn query(&self) -> DepGraphQuery { + pub fn query(&self) -> DepGraphQuery { let edges: Vec<_> = self.edges.iter() .map(|&(i, j)| (self.id(i), self.id(j))) .collect(); diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index dc482b0d6ac85..6afd31bfe92df 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -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 { + 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) -> Option> { + pub fn in_task<'graph>(&'graph self, key: DepNode) -> Option> { raii::DepTask::new(&self.data.thread, key) } @@ -103,14 +102,14 @@ impl DepGraph { /// `arg` parameter. /// /// [README]: README.md - pub fn with_task(&self, key: DepNode, cx: C, arg: A, task: fn(C, A) -> R) -> R + pub fn with_task(&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) { + pub fn read(&self, v: DepNode) { if self.data.thread.is_enqueue_enabled() { self.data.thread.enqueue(DepMessage::Read(v)); } diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs index 809bed939f54c..92b05f6a6558e 100644 --- a/src/librustc/dep_graph/mod.rs +++ b/src/librustc/dep_graph/mod.rs @@ -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}; diff --git a/src/librustc/dep_graph/query.rs b/src/librustc/dep_graph/query.rs index 4c791f9655342..116c527bf46d5 100644 --- a/src/librustc/dep_graph/query.rs +++ b/src/librustc/dep_graph/query.rs @@ -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 { - pub graph: Graph, ()>, - pub indices: FxHashMap, NodeIndex>, +pub struct DepGraphQuery { + pub graph: Graph, + pub indices: FxHashMap, } -impl DepGraphQuery { - pub fn new(nodes: &[DepNode], - edges: &[(DepNode, DepNode)]) - -> DepGraphQuery { +impl DepGraphQuery { + pub fn new(nodes: &[DepNode], + edges: &[(DepNode, DepNode)]) + -> DepGraphQuery { let mut graph = Graph::new(); let mut indices = FxHashMap(); for node in nodes { @@ -43,18 +41,18 @@ impl DepGraphQuery { } } - pub fn contains_node(&self, node: &DepNode) -> bool { + pub fn contains_node(&self, node: &DepNode) -> bool { self.indices.contains_key(&node) } - pub fn nodes(&self) -> Vec<&DepNode> { + pub fn nodes(&self) -> Vec<&DepNode> { self.graph.all_nodes() .iter() .map(|n| &n.data) .collect() } - pub fn edges(&self) -> Vec<(&DepNode,&DepNode)> { + pub fn edges(&self) -> Vec<(&DepNode,&DepNode)> { self.graph.all_edges() .iter() .map(|edge| (edge.source(), edge.target())) @@ -63,7 +61,7 @@ impl DepGraphQuery { .collect() } - fn reachable_nodes(&self, node: &DepNode, direction: Direction) -> Vec<&DepNode> { + 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 DepGraphQuery { /// 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) -> Vec<&DepNode> { + 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) -> Vec<&DepNode> { + 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) -> Vec<&DepNode> { + 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)) diff --git a/src/librustc/dep_graph/raii.rs b/src/librustc/dep_graph/raii.rs index e39797599acfd..b45f5de802714 100644 --- a/src/librustc/dep_graph/raii.rs +++ b/src/librustc/dep_graph/raii.rs @@ -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>, + key: Option, } impl<'graph> DepTask<'graph> { - pub fn new(data: &'graph DepGraphThreadData, key: DepNode) + pub fn new(data: &'graph DepGraphThreadData, key: DepNode) -> Option> { if data.is_enqueue_enabled() { data.enqueue(DepMessage::PushTask(key.clone())); diff --git a/src/librustc/dep_graph/shadow.rs b/src/librustc/dep_graph/shadow.rs index bedb6ff2771f0..8808ea5948da8 100644 --- a/src/librustc/dep_graph/shadow.rs +++ b/src/librustc/dep_graph/shadow.rs @@ -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>>>, + stack: RefCell>>, forbidden_edge: Option, } @@ -114,8 +113,8 @@ impl ShadowGraph { } fn check_edge(&self, - source: Option>>, - target: Option>>) { + source: Option>, + target: Option>) { 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>> { +fn top<'s>(stack: &'s Vec>) -> Option> { stack.last() - .map(|n: &'s Option>| -> Option<&'s DepNode> { + .map(|n: &'s Option| -> Option<&'s DepNode> { // (*) // (*) type annotation just there to clarify what would // otherwise be some *really* obscure code diff --git a/src/librustc/dep_graph/thread.rs b/src/librustc/dep_graph/thread.rs index d3a940c811b88..ad0abfe26f45f 100644 --- a/src/librustc/dep_graph/thread.rs +++ b/src/librustc/dep_graph/thread.rs @@ -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), - Write(DepNode), - PushTask(DepNode), - PopTask(DepNode), + Read(DepNode), + Write(DepNode), + PushTask(DepNode), + PopTask(DepNode), PushIgnore, PopIgnore, Query, @@ -63,7 +62,7 @@ pub struct DepGraphThreadData { swap_out: Sender>, // where to receive query results - query_in: Receiver>, + query_in: Receiver, } const INITIAL_CAPACITY: usize = 2048; @@ -120,7 +119,7 @@ impl DepGraphThreadData { self.swap_out.send(old_messages).unwrap(); } - pub fn query(&self) -> DepGraphQuery { + 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>, swap_out: Sender>, - query_out: Sender>) { + query_out: Sender) { let mut edges = DepGraphEdges::new(); // the compiler thread always expects a fresh buffer to be diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 176760c255c00..a1875cd46a0cb 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -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 { + 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 { - 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 { diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 2022565d533bc..06506e214ed39 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -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); diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index c2fe04534375f..16ecc94b9476a 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -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 diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 998201ad8d9ff..10710d963a015 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -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; } diff --git a/src/librustc/traits/trans/mod.rs b/src/librustc/traits/trans/mod.rs index 7ad2ef90f0d49..e3b7757ec5b72 100644 --- a/src/librustc/traits/trans/mod.rs +++ b/src/librustc/traits/trans/mod.rs @@ -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 { - 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 { + 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 }) } } diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 7dca28df9da39..76103148ec3e8 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -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 { + 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), diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index b5adcc8ed757d..162a734aa195b 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -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 { - 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 { - DepNode::CoherenceCheckTrait(def_id) +fn type_param_predicates((item_id, param_id): (DefId, DefId)) -> DepConstructor { + DepConstructor::TypeParamPredicates { + item_id, + param_id + } +} + +fn coherent_trait_dep_node((_, def_id): (CrateNum, DefId)) -> DepConstructor { + DepConstructor::CoherenceCheckTrait(def_id) } -fn crate_inherent_impls_dep_node(_: CrateNum) -> DepNode { - DepNode::Coherence +fn crate_inherent_impls_dep_node(_: CrateNum) -> DepConstructor { + DepConstructor::Coherence } -fn reachability_dep_node(_: CrateNum) -> DepNode { - DepNode::Reachability +fn reachability_dep_node(_: CrateNum) -> DepConstructor { + DepConstructor::Reachability } -fn mir_shim_dep_node(instance: ty::InstanceDef) -> DepNode { +fn mir_shim_dep_node(instance: ty::InstanceDef) -> DepConstructor { instance.dep_node() } -fn symbol_name_dep_node(instance: ty::Instance) -> DepNode { +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 { - DepNode::TypeckBodiesKrate +fn typeck_item_bodies_dep_node(_: CrateNum) -> DepConstructor { + DepConstructor::TypeckBodiesKrate } -fn const_eval_dep_node((def_id, _): (DefId, &Substs)) -> DepNode { - DepNode::ConstEval(def_id) +fn const_eval_dep_node((def_id, _): (DefId, &Substs)) -> DepConstructor { + DepConstructor::ConstEval(def_id) } -fn mir_keys(_: CrateNum) -> DepNode { - DepNode::MirKeys +fn mir_keys(_: CrateNum) -> DepConstructor { + DepConstructor::MirKeys } -fn crate_variances(_: CrateNum) -> DepNode { - DepNode::CrateVariances +fn crate_variances(_: CrateNum) -> DepConstructor { + DepConstructor::CrateVariances } -fn relevant_trait_impls_for((def_id, _): (DefId, SimplifiedType)) -> DepNode { - 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 { +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 { +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 { +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 { +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 { +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) } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index afa2da3d561b7..b09ab57cc41aa 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -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 { + 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> + 'a { @@ -952,9 +952,9 @@ impl<'tcx> PolyTraitPredicate<'tcx> { self.0.def_id() } - pub fn dep_node(&self) -> DepNode { + 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) } } diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs index 17564671a1e36..40ee3cd28f562 100644 --- a/src/librustc/util/common.rs +++ b/src/librustc/util/common.rs @@ -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(&self, key: Self::Key, op: OP) -> Self::Value + fn memoize(&self, tcx: TyCtxt, key: Self::Key, op: OP) -> Self::Value where OP: FnOnce() -> Self::Value; } @@ -219,7 +221,7 @@ impl MemoizationMap for RefCell> type Key = K; type Value = V; - fn memoize(&self, key: K, op: OP) -> V + fn memoize(&self, _tcx: TyCtxt, key: K, op: OP) -> V where OP: FnOnce() -> V { let result = self.borrow().get(&key).cloned(); diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs index 39fe2188f68d1..04192c35ef3ab 100644 --- a/src/librustc_incremental/assert_dep_graph.rs +++ b/src/librustc_incremental/assert_dep_graph.rs @@ -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)>; -type Targets = Vec<(Span, ast::Name, ast::NodeId, DepNode)>; +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>, - Vec<(&'q DepNode, &'q DepNode)>); +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; - type Edge = (&'q DepNode, &'q DepNode); - fn nodes(&self) -> dot::Nodes<&'q DepNode> { + 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, &'q DepNode)> { + fn edges(&self) -> dot::Edges<(&'q DepNode, &'q DepNode)> { self.1[..].into_cow() } - fn source(&self, edge: &(&'q DepNode, &'q DepNode)) -> &'q DepNode { + fn source(&self, edge: &(&'q DepNode, &'q DepNode)) -> &'q DepNode { edge.0 } - fn target(&self, edge: &(&'q DepNode, &'q DepNode)) -> &'q DepNode { + 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; - type Edge = (&'q DepNode, &'q DepNode); + 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) -> 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) -> 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, filter: &DepNodeFilter) - -> Option>> +fn node_set<'q>(query: &'q DepGraphQuery, filter: &DepNodeFilter) + -> Option> { debug!("node_set(filter={:?})", filter); @@ -318,10 +319,10 @@ fn node_set<'q>(query: &'q DepGraphQuery, filter: &DepNodeFilter) Some(query.nodes().into_iter().filter(|n| filter.test(n)).collect()) } -fn filter_nodes<'q>(query: &'q DepGraphQuery, - sources: &Option>>, - targets: &Option>>) - -> FxHashSet<&'q DepNode> +fn filter_nodes<'q>(query: &'q DepGraphQuery, + sources: &Option>, + targets: &Option>) + -> 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, } } -fn walk_nodes<'q>(query: &'q DepGraphQuery, - starts: &FxHashSet<&'q DepNode>, +fn walk_nodes<'q>(query: &'q DepGraphQuery, + starts: &FxHashSet<&'q DepNode>, direction: Direction) - -> FxHashSet<&'q DepNode> + -> FxHashSet<&'q DepNode> { let mut set = FxHashSet(); for &start in starts { @@ -360,10 +361,10 @@ fn walk_nodes<'q>(query: &'q DepGraphQuery, set } -fn walk_between<'q>(query: &'q DepGraphQuery, - sources: &FxHashSet<&'q DepNode>, - targets: &FxHashSet<&'q DepNode>) - -> FxHashSet<&'q DepNode> +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, }) .collect(); - fn recurse(query: &DepGraphQuery, + fn recurse(query: &DepGraphQuery, node_states: &mut [State], node: NodeIndex) -> bool @@ -428,9 +429,9 @@ fn walk_between<'q>(query: &'q DepGraphQuery, } } -fn filter_edges<'q>(query: &'q DepGraphQuery, - nodes: &FxHashSet<&'q DepNode>) - -> Vec<(&'q DepNode, &'q DepNode)> +fn filter_edges<'q>(query: &'q DepGraphQuery, + nodes: &FxHashSet<&'q DepNode>) + -> Vec<(&'q DepNode, &'q DepNode)> { query.edges() .into_iter() diff --git a/src/librustc_incremental/calculate_svh/mod.rs b/src/librustc_incremental/calculate_svh/mod.rs index 7831ae3092f4e..f30a0f553b982 100644 --- a/src/librustc_incremental/calculate_svh/mod.rs +++ b/src/librustc_incremental/calculate_svh/mod.rs @@ -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; pub struct IncrementalHashesMap { - hashes: FxHashMap, Fingerprint>, + hashes: FxHashMap, // 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) -> Option<&Fingerprint> { + pub fn get(&self, k: &DepNode) -> Option<&Fingerprint> { self.hashes.get(k) } - pub fn insert(&mut self, k: DepNode, v: Fingerprint) -> Option { - 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, 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> for IncrementalHashesMap { +impl<'a> ::std::ops::Index<&'a DepNode> for IncrementalHashesMap { type Output = Fingerprint; - fn index(&self, index: &'a DepNode) -> &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(&mut self, - dep_node: DepNode, + dep_node: DepNode, hash_bodies: bool, item_like: T) where T: HashStable> @@ -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 to a - // DepNode 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); diff --git a/src/librustc_incremental/persist/data.rs b/src/librustc_incremental/persist/data.rs index 96b7de94daf65..c3cd9656afe55 100644 --- a/src/librustc_incremental/persist/data.rs +++ b/src/librustc_incremental/persist/data.rs @@ -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>, + pub nodes: IndexVec, /// 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>, + pub bootstrap_outputs: Vec, /// 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, + pub dep_node: DepNode, /// the hash as of previous compilation, computed by code in /// `hash` module diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index 3a428bd7b8f7d..01ec0d685268a 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -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> = + let dirty_inputs: FxHashSet = 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, - dirty_inputs: FxHashSet>, + query: &'a DepGraphQuery, + dirty_inputs: FxHashSet, checked_attrs: FxHashSet, } impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> { - fn dep_node(&self, attr: &Attribute, def_id: DefId) -> DepNode { + 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) -> DepNode { - 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) { + 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) { + 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)); } } diff --git a/src/librustc_incremental/persist/hash.rs b/src/librustc_incremental/persist/hash.rs index 4a2dd274aae52..0e8ffb9ee3c96 100644 --- a/src/librustc_incremental/persist/hash.rs +++ b/src/librustc_incremental/persist/hash.rs @@ -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) -> 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) -> Option { - match *dep_node { - DepNode::Krate => { + pub fn hash(&mut self, dep_node: &DepNode) -> Option { + 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 + } } _ => { diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs index f2ecf4c74e781..53fccfaa39292 100644 --- a/src/librustc_incremental/persist/load.rs +++ b/src/librustc_incremental/persist/load.rs @@ -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>; +pub type DirtyNodes = FxHashMap; /// 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> { 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) -> Option> { - 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, Vec>> = { + let edge_map: FxHashMap> = { let capacity = serialized_dep_graph.edge_list_data.len(); let mut edge_map = FxHashMap::with_capacity_and_hasher(capacity, Default::default()); @@ -194,48 +199,28 @@ 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()); - } + if let DepKind::WorkProduct = bootstrap_output.kind { + let wp_id = WorkProductId::from_fingerprint(bootstrap_output.hash); + clean_work_products.insert(wp_id); + } - tcx.dep_graph.with_task(n, (), (), create_node); + tcx.dep_graph.with_task(*bootstrap_output, (), (), create_node); - fn create_node((): (), (): ()) { - // just create the node with no inputs - } + fn create_node((): (), (): ()) { + // just create the node with no inputs } } - // 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); - } - // Add in work-products that are still clean, and delete those that are // dirty. reconcile_work_products(tcx, work_products, &clean_work_products); @@ -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); - } + continue; + } - 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); + 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, Vec>>, +fn transitive_dirty_nodes(edge_map: &FxHashMap>, mut dirty_nodes: DirtyNodes) -> DirtyNodes { - let mut stack: Vec<(DepNode, DepNode)> = 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) { 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, - target: &'edges DepNode, - edges: &'edges FxHashMap, Vec>>, + source: &'edges DepNode, + target: &'edges DepNode, dirty_raw_nodes: &DirtyNodes, clean_work_products: &mut FxHashSet, - dirty_work_products: &mut FxHashSet, - extra_edges: &mut Vec<(&'edges DepNode, &'edges DepNode)>) + dirty_work_products: &mut FxHashSet) { // 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)); - - // 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))); + // 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: + + // 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. } } diff --git a/src/librustc_incremental/persist/preds/mod.rs b/src/librustc_incremental/persist/preds/mod.rs index e769641a4cadf..0a259ad268582 100644 --- a/src/librustc_incremental/persist/preds/mod.rs +++ b/src/librustc_incremental/persist/preds/mod.rs @@ -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, ()>, + 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>, + pub bootstrap_outputs: Vec<&'query DepNode>, // For the inputs (hir/foreign-metadata), we include hashes. - pub hashes: FxHashMap<&'query DepNode, Fingerprint>, + pub hashes: FxHashMap<&'query DepNode, Fingerprint>, } impl<'q> Predecessors<'q> { - pub fn new(query: &'q DepGraphQuery, 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| -> 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> = + let bootstrap_outputs: Vec<&'q DepNode> = (0 .. graph.len_nodes()) .map(NodeIndex) .filter(|&n| graph.incoming_edges(n).next().is_none()) diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs index 01db756f9de04..48742b424f1e5 100644 --- a/src/librustc_incremental/persist/save.rs +++ b/src/librustc_incremental/persist/save.rs @@ -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| { - 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> = preds + let nodes: IndexVec = 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, } }) diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index ed67616e58f64..e572be9ffe7d1 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -255,6 +255,13 @@ impl CStore { pub fn do_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option { 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 { diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 60cc03f7b7929..97f73b25c64d7 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -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::() @@ -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 { - 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 { - 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) diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index a095fdd508417..2a2010621fcce 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -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 { + 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) } } diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 9180f9100ad71..1337f90efa74d 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -203,7 +203,7 @@ impl Tracked { } } - pub fn get(&self, dep_graph: &DepGraph, dep_node: DepNode) -> &T { + pub fn get(&self, dep_graph: &DepGraph, dep_node: DepNode) -> &T { dep_graph.read(dep_node); &self.state } diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index e57cbb1c91013..e4939db5759a5 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -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; diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index df8984e6d2479..ead442d338820 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -167,8 +167,8 @@ impl<'tcx> CodegenUnit<'tcx> { WorkProductId::from_cgu_name(self.name()) } - pub fn work_product_dep_node(&self) -> DepNode { - 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, diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 392ee71d52b44..2a36ef9358e45 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -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); } diff --git a/src/librustc_typeck/coherence/inherent_impls.rs b/src/librustc_typeck/coherence/inherent_impls.rs index f7ebc21044222..e24d766002187 100644 --- a/src/librustc_typeck/coherence/inherent_impls.rs +++ b/src/librustc_typeck/coherence/inherent_impls.rs @@ -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 diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs index ba1d7b18e8c7f..781e323dea392 100644 --- a/src/librustc_typeck/coherence/overlap.rs +++ b/src/librustc_typeck/coherence/overlap.rs @@ -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. diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index cb2ee7dd1bcda..c434edb1c31ab 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -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); diff --git a/src/librustc_typeck/variance/mod.rs b/src/librustc_typeck/variance/mod.rs index 1afe2725ac87d..8f9f40ca40b03 100644 --- a/src/librustc_typeck/variance/mod.rs +++ b/src/librustc_typeck/variance/mod.rs @@ -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); } } diff --git a/src/test/incremental/dirty_clean.rs b/src/test/incremental/dirty_clean.rs index 9f20128de4f55..ce9865103dcc8 100644 --- a/src/test/incremental/dirty_clean.rs +++ b/src/test/incremental/dirty_clean.rs @@ -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 } } From 7f482808f9700259da6585597486166148576d96 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 9 Jun 2017 15:01:44 +0200 Subject: [PATCH 2/3] incr.comp.: Clean up and optimize dep-graph loading. --- src/librustc_incremental/persist/data.rs | 21 ++-- .../persist/dirty_clean.rs | 13 +- src/librustc_incremental/persist/load.rs | 114 ++++++++---------- src/librustc_incremental/persist/save.rs | 57 ++++++--- 4 files changed, 116 insertions(+), 89 deletions(-) diff --git a/src/librustc_incremental/persist/data.rs b/src/librustc_incremental/persist/data.rs index c3cd9656afe55..06acfb5d77807 100644 --- a/src/librustc_incremental/persist/data.rs +++ b/src/librustc_incremental/persist/data.rs @@ -26,7 +26,7 @@ pub struct SerializedDepGraph { /// 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. - pub edge_list_indices: Vec<(u32, u32)>, + pub edge_list_indices: IndexVec, /// A flattened list of all edge targets in the graph. Edge sources are /// implicit in edge_list_indices. pub edge_list_data: Vec, @@ -55,7 +55,14 @@ pub struct SerializedDepGraph { /// will be different when we next compile) related to each node, /// but rather the `DefPathIndex`. This can then be retraced /// to find the current def-id. - pub hashes: Vec, + pub hashes: Vec<(DepNodeIndex, Fingerprint)>, +} + +impl SerializedDepGraph { + pub fn edge_targets_from(&self, source: DepNodeIndex) -> &[DepNodeIndex] { + let targets = self.edge_list_indices[source]; + &self.edge_list_data[targets.0 as usize .. targets.1 as usize] + } } /// The index of a DepNode in the SerializedDepGraph::nodes array. @@ -84,16 +91,6 @@ impl Idx for DepNodeIndex { } } -#[derive(Debug, RustcEncodable, RustcDecodable)] -pub struct SerializedHash { - /// def-id of thing being hashed - pub dep_node: DepNode, - - /// the hash as of previous compilation, computed by code in - /// `hash` module - pub hash: Fingerprint, -} - #[derive(Debug, RustcEncodable, RustcDecodable)] pub struct SerializedWorkProduct { /// node that produced the work-product diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index 01ec0d685268a..3f3dc10365c67 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -40,6 +40,7 @@ //! previous revision to compare things to. //! +use super::data::DepNodeIndex; use super::load::DirtyNodes; use rustc::dep_graph::{DepGraphQuery, DepNode, DepKind}; use rustc::hir; @@ -50,6 +51,7 @@ use rustc::ich::{Fingerprint, ATTR_DIRTY, ATTR_CLEAN, ATTR_DIRTY_METADATA, ATTR_CLEAN_METADATA}; use syntax::ast::{self, Attribute, NestedMetaItem}; use rustc_data_structures::fx::{FxHashSet, FxHashMap}; +use rustc_data_structures::indexed_vec::IndexVec; use syntax_pos::Span; use rustc::ty::TyCtxt; @@ -57,6 +59,7 @@ const LABEL: &'static str = "label"; const CFG: &'static str = "cfg"; pub fn check_dirty_clean_annotations<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + nodes: &IndexVec, dirty_inputs: &DirtyNodes) { // can't add `#[rustc_dirty]` etc without opting in to this feature if !tcx.sess.features.borrow().rustc_attrs { @@ -66,8 +69,14 @@ pub fn check_dirty_clean_annotations<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let _ignore = tcx.dep_graph.in_ignore(); let dirty_inputs: FxHashSet = dirty_inputs.keys() - .filter(|dep_node| dep_node.extract_def_id(tcx).is_some()) - .cloned() + .filter_map(|dep_node_index| { + let dep_node = nodes[*dep_node_index]; + if dep_node.extract_def_id(tcx).is_some() { + Some(dep_node) + } else { + None + } + }) .collect(); let query = tcx.dep_graph.query(); diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs index 53fccfaa39292..28a00bf4aa6c8 100644 --- a/src/librustc_incremental/persist/load.rs +++ b/src/librustc_incremental/persist/load.rs @@ -17,9 +17,9 @@ use rustc::ich::Fingerprint; use rustc::session::Session; use rustc::ty::TyCtxt; use rustc_data_structures::fx::{FxHashSet, FxHashMap}; +use rustc_data_structures::indexed_vec::IndexVec; use rustc_serialize::Decodable as RustcDecodable; use rustc_serialize::opaque::Decoder; -use std::default::Default; use std::path::{Path}; use IncrementalHashesMap; @@ -32,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; +pub type DirtyNodes = FxHashMap; /// If we are in incremental mode, and a previous dep-graph exists, /// then load up those nodes/edges that are still valid into the @@ -166,48 +166,35 @@ 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> = { - let capacity = serialized_dep_graph.edge_list_data.len(); - let mut edge_map = FxHashMap::with_capacity_and_hasher(capacity, Default::default()); - - for (node_index, source) in serialized_dep_graph.nodes.iter().enumerate() { - let (start, end) = serialized_dep_graph.edge_list_indices[node_index]; - let targets = - (&serialized_dep_graph.edge_list_data[start as usize .. end as usize]) - .into_iter() - .map(|&node_index| serialized_dep_graph.nodes[node_index].clone()) - .collect(); - - edge_map.insert(source.clone(), targets); - } - - edge_map - }; - // Compute the set of nodes from the old graph where some input - // has changed or been removed. These are "raw" source nodes, - // which means that they still use the original `DefPathIndex` - // values from the encoding, rather than having been retraced to a - // `DefId`. The reason for this is that this way we can include - // nodes that have been removed (which no longer have a `DefId` in - // the current compilation). + // has changed or been removed. let dirty_raw_nodes = initial_dirty_nodes(tcx, incremental_hashes_map, + &serialized_dep_graph.nodes, &serialized_dep_graph.hashes); - let dirty_raw_nodes = transitive_dirty_nodes(&edge_map, dirty_raw_nodes); + let dirty_raw_nodes = transitive_dirty_nodes(&serialized_dep_graph, + dirty_raw_nodes); // 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 - for (source, targets) in &edge_map { - for target in targets { - process_edge(tcx, source, target, &dirty_raw_nodes, - &mut clean_work_products, &mut dirty_work_products); + for (source, targets) in serialized_dep_graph.edge_list_indices.iter_enumerated() { + let target_begin = targets.0 as usize; + let target_end = targets.1 as usize; + + for &target in &serialized_dep_graph.edge_list_data[target_begin .. target_end] { + process_edge(tcx, + source, + target, + &serialized_dep_graph.nodes, + &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). + // 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 DepKind::WorkProduct = bootstrap_output.kind { let wp_id = WorkProductId::from_fingerprint(bootstrap_output.hash); @@ -225,7 +212,9 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // dirty. reconcile_work_products(tcx, work_products, &clean_work_products); - dirty_clean::check_dirty_clean_annotations(tcx, &dirty_raw_nodes); + dirty_clean::check_dirty_clean_annotations(tcx, + &serialized_dep_graph.nodes, + &dirty_raw_nodes); load_prev_metadata_hashes(tcx, &mut *incremental_hashes_map.prev_metadata_hashes.borrow_mut()); @@ -236,19 +225,20 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, /// a bit vector where the index is the DefPathIndex. fn initial_dirty_nodes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, incremental_hashes_map: &IncrementalHashesMap, - serialized_hashes: &[SerializedHash]) + nodes: &IndexVec, + serialized_hashes: &[(DepNodeIndex, Fingerprint)]) -> DirtyNodes { let mut hcx = HashContext::new(tcx, incremental_hashes_map); let mut dirty_nodes = FxHashMap(); - for hash in serialized_hashes { - let dep_node = hash.dep_node; + for &(dep_node_index, prev_hash) in serialized_hashes { + let dep_node = nodes[dep_node_index]; 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 { + if current_hash == prev_hash { debug!("initial_dirty_nodes: {:?} is clean (hash={:?})", dep_node, current_hash); @@ -259,13 +249,13 @@ fn initial_dirty_nodes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, println!("node {:?} is dirty as hash is {:?}, was {:?}", dep_node, current_hash, - hash.hash); + prev_hash); } debug!("initial_dirty_nodes: {:?} is dirty as hash is {:?}, was {:?}", dep_node, current_hash, - hash.hash); + prev_hash); } else { if tcx.sess.opts.debugging_opts.incremental_dump_hash { println!("node {:?} is dirty as it was removed", dep_node); @@ -273,30 +263,27 @@ fn initial_dirty_nodes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, debug!("initial_dirty_nodes: {:?} is dirty as it was removed", dep_node); } - - dirty_nodes.insert(hash.dep_node.clone(), hash.dep_node.clone()); + dirty_nodes.insert(dep_node_index, dep_node_index); } dirty_nodes } -fn transitive_dirty_nodes(edge_map: &FxHashMap>, +fn transitive_dirty_nodes(serialized_dep_graph: &SerializedDepGraph, mut dirty_nodes: DirtyNodes) -> DirtyNodes { - let mut stack: Vec<(DepNode, DepNode)> = vec![]; - stack.extend(dirty_nodes.iter().map(|(s, b)| (s.clone(), b.clone()))); + let mut stack: Vec<(DepNodeIndex, DepNodeIndex)> = vec![]; + stack.extend(dirty_nodes.iter().map(|(&s, &b)| (s, b))); while let Some((source, blame)) = stack.pop() { // we know the source is dirty (because of the node `blame`)... - assert!(dirty_nodes.contains_key(&source)); + debug_assert!(dirty_nodes.contains_key(&source)); // ...so we dirty all the targets (with the same blame) - if let Some(targets) = edge_map.get(&source) { - for target in targets { - if !dirty_nodes.contains_key(target) { - dirty_nodes.insert(target.clone(), blame.clone()); - stack.push((target.clone(), blame.clone())); - } + for &target in serialized_dep_graph.edge_targets_from(source) { + if !dirty_nodes.contains_key(&target) { + dirty_nodes.insert(target, blame); + stack.push((target, blame)); } } } @@ -402,8 +389,9 @@ fn load_prev_metadata_hashes(tcx: TyCtxt, fn process_edge<'a, 'tcx, 'edges>( tcx: TyCtxt<'a, 'tcx, 'tcx>, - source: &'edges DepNode, - target: &'edges DepNode, + source: DepNodeIndex, + target: DepNodeIndex, + nodes: &IndexVec, dirty_raw_nodes: &DirtyNodes, clean_work_products: &mut FxHashSet, dirty_work_products: &mut FxHashSet) @@ -411,7 +399,8 @@ fn process_edge<'a, 'tcx, 'edges>( // 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 Some(&blame) = dirty_raw_nodes.get(&target) { + let target = nodes[target]; if let DepKind::WorkProduct = target.kind { if tcx.sess.opts.debugging_opts.incremental_info { let wp_id = WorkProductId::from_fingerprint(target.hash); @@ -420,6 +409,7 @@ fn process_edge<'a, 'tcx, 'edges>( // Try to reconstruct the human-readable version of the // DepNode. This cannot be done for things that where // removed. + let blame = nodes[blame]; let blame_str = if let Some(def_id) = blame.extract_def_id(tcx) { format!("{:?}({})", blame.kind, @@ -444,21 +434,23 @@ fn process_edge<'a, 'tcx, 'edges>( // 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)); + 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 { + debug_assert!(match nodes[source].kind { DepKind::Hir | DepKind::HirBody | DepKind::MetaData => { - does_still_exist(tcx, source) + does_still_exist(tcx, &nodes[source]) } _ => true, }); - if !dirty_raw_nodes.contains_key(target) { - let _task = tcx.dep_graph.in_task(*target); - tcx.dep_graph.read(*source); + if !dirty_raw_nodes.contains_key(&target) { + let target = nodes[target]; + let source = nodes[source]; + 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); diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs index 48742b424f1e5..867452d97e8fb 100644 --- a/src/librustc_incremental/persist/save.rs +++ b/src/librustc_incremental/persist/save.rs @@ -174,14 +174,14 @@ pub fn encode_dep_graph(tcx: TyCtxt, tcx.sess.opts.dep_tracking_hash().encode(encoder)?; // NB: We rely on this Vec being indexable by reduced_graph's NodeIndex. - let nodes: IndexVec = preds + let mut nodes: IndexVec = preds .reduced_graph .all_nodes() .iter() .map(|node| node.data.clone()) .collect(); - let mut edge_list_indices = Vec::with_capacity(nodes.len()); + let mut edge_list_indices = IndexVec::with_capacity(nodes.len()); let mut edge_list_data = Vec::with_capacity(preds.reduced_graph.len_edges()); for node_index in 0 .. nodes.len() { @@ -196,7 +196,7 @@ pub fn encode_dep_graph(tcx: TyCtxt, edge_list_indices.push((start, end)); } - // Let's make we had no overflow there. + // Let's make sure we had no overflow there. assert!(edge_list_data.len() <= ::std::u32::MAX as usize); // Check that we have a consistent number of edges. assert_eq!(edge_list_data.len(), preds.reduced_graph.len_edges()); @@ -206,23 +206,52 @@ pub fn encode_dep_graph(tcx: TyCtxt, .map(|dep_node| (**dep_node).clone()) .collect(); - let hashes = preds - .hashes - .iter() - .map(|(&dep_node, &hash)| { - SerializedHash { - dep_node: dep_node.clone(), - hash: hash, - } - }) - .collect(); + // Next, build the map of content hashes. To this end, we need to transform + // the (DepNode -> Fingerprint) map that we have into a + // (DepNodeIndex -> Fingerprint) map. This may necessitate adding nodes back + // to the dep-graph that have been filtered out during reduction. + let content_hashes = { + // We have to build a (DepNode -> DepNodeIndex) map. We over-allocate a + // little because we expect some more nodes to be added. + let capacity = (nodes.len() * 120) / 100; + let mut node_to_index = FxHashMap::with_capacity_and_hasher(capacity, + Default::default()); + // Add the nodes we already have in the graph. + node_to_index.extend(nodes.iter_enumerated() + .map(|(index, &node)| (node, index))); + + let mut content_hashes = Vec::with_capacity(preds.hashes.len()); + + for (&&dep_node, &hash) in preds.hashes.iter() { + let dep_node_index = *node_to_index + .entry(dep_node) + .or_insert_with(|| { + // There is no DepNodeIndex for this DepNode yet. This + // happens when the DepNode got filtered out during graph + // reduction. Since we have a content hash for the DepNode, + // we add it back to the graph. + let next_index = nodes.len(); + nodes.push(dep_node); + + debug_assert_eq!(next_index, edge_list_indices.len()); + // Push an empty list of edges + edge_list_indices.push((0,0)); + + DepNodeIndex::new(next_index) + }); + + content_hashes.push((dep_node_index, hash)); + } + + content_hashes + }; let graph = SerializedDepGraph { nodes, edge_list_indices, edge_list_data, bootstrap_outputs, - hashes, + hashes: content_hashes, }; // Encode the graph data. From fdff2d3588451c49adca5d92f551af94e920f0e8 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 9 Jun 2017 17:58:49 +0200 Subject: [PATCH 3/3] Add some documentation to the dep_node module. --- src/librustc/dep_graph/dep_node.rs | 52 ++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 5f3dd9052034f..3b6a7f87c13a5 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -8,6 +8,58 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. + +//! This module defines the `DepNode` type which the compiler uses to represent +//! nodes in the dependency graph. A `DepNode` consists of a `DepKind` (which +//! specifies the kind of thing it represents, like a piece of HIR, MIR, etc) +//! and a `Fingerprint`, a 128 bit hash value the exact meaning of which +//! depends on the node's `DepKind`. Together, the kind and the fingerprint +//! fully identify a dependency node, even across multiple compilation sessions. +//! In other words, the value of the fingerprint does not depend on anything +//! that is specific to a given compilation session, like an unpredictable +//! interning key (e.g. NodeId, DefId, Symbol) or the numeric value of a +//! pointer. The concept behind this could be compared to how git commit hashes +//! uniquely identify a given commit and has a few advantages: +//! +//! * A `DepNode` can simply be serialized to disk and loaded in another session +//! without the need to do any "rebasing (like we have to do for Spans and +//! NodeIds) or "retracing" like we had to do for `DefId` in earlier +//! implementations of the dependency graph. +//! * A `Fingerprint` is just a bunch of bits, which allows `DepNode` to +//! implement `Copy`, `Sync`, `Send`, `Freeze`, etc. +//! * Since we just have a bit pattern, `DepNode` can be mapped from disk into +//! memory without any post-processing (e.g. "abomination-style" pointer +//! reconstruction). +//! * Because a `DepNode` is self-contained, we can instantiate `DepNodes` that +//! refer to things that do not exist anymore. In previous implementations +//! `DepNode` contained a `DefId`. A `DepNode` referring to something that +//! had been removed between the previous and the current compilation session +//! could not be instantiated because the current compilation session +//! contained no `DefId` for thing that had been removed. +//! +//! `DepNode` definition happens in the `define_dep_nodes!()` macro. This macro +//! defines the `DepKind` enum and a corresponding `DepConstructor` enum. The +//! `DepConstructor` enum links a `DepKind` to the parameters that are needed at +//! runtime in order to construct a valid `DepNode` fingerprint. +//! +//! Because the macro sees what parameters a given `DepKind` requires, it can +//! "infer" some properties for each kind of `DepNode`: +//! +//! * Whether a `DepNode` of a given kind has any parameters at all. Some +//! `DepNode`s, like `Krate`, represent global concepts with only one value. +//! * Whether it is possible, in principle, to reconstruct a query key from a +//! given `DepNode`. Many `DepKind`s only require a single `DefId` parameter, +//! in which case it is possible to map the node's fingerprint back to the +//! `DefId` it was computed from. In other cases, too much information gets +//! lost during fingerprint computation. +//! +//! The `DepConstructor` enum, together with `DepNode::new()` ensures that only +//! valid `DepNode` instances can be constructed. For example, the API does not +//! allow for constructing parameterless `DepNode`s with anything other +//! than a zeroed out fingerprint. More generally speaking, it relieves the +//! user of the `DepNode` API of having to know how to compute the expected +//! fingerprint for a given set of node parameters. + use hir::def_id::{CrateNum, DefId}; use hir::map::DefPathHash;