about summary refs log tree commit diff
diff options
context:
space:
mode:
authorCamille GILLOT <gillot.camille@gmail.com>2019-12-31 10:51:58 +0100
committerCamille GILLOT <gillot.camille@gmail.com>2020-03-23 23:07:19 +0100
commita7e2641b9aba10d6eabf6978d3b5506d99ae633c (patch)
treeafd0f9b19c7798935bbc4474b97b2fd62e760cf5
parent1edd389cc4c7b5be7a3dd4fe4b986f6017018e54 (diff)
downloadrust-a7e2641b9aba10d6eabf6978d3b5506d99ae633c.tar.gz
rust-a7e2641b9aba10d6eabf6978d3b5506d99ae633c.zip
Move dep_graph to new crate librustc_query_system.
-rw-r--r--src/librustc_query_system/dep_graph/README.md (renamed from src/librustc/dep_graph/README.md)0
-rw-r--r--src/librustc_query_system/dep_graph/debug.rs (renamed from src/librustc/dep_graph/debug.rs)0
-rw-r--r--src/librustc_query_system/dep_graph/dep_node.rs520
-rw-r--r--src/librustc_query_system/dep_graph/graph.rs (renamed from src/librustc/dep_graph/graph.rs)0
-rw-r--r--src/librustc_query_system/dep_graph/mod.rs (renamed from src/librustc/dep_graph/mod.rs)0
-rw-r--r--src/librustc_query_system/dep_graph/prev.rs (renamed from src/librustc/dep_graph/prev.rs)0
-rw-r--r--src/librustc_query_system/dep_graph/query.rs (renamed from src/librustc/dep_graph/query.rs)0
-rw-r--r--src/librustc_query_system/dep_graph/safe.rs (renamed from src/librustc/dep_graph/safe.rs)0
-rw-r--r--src/librustc_query_system/dep_graph/serialized.rs (renamed from src/librustc/dep_graph/serialized.rs)0
9 files changed, 520 insertions, 0 deletions
diff --git a/src/librustc/dep_graph/README.md b/src/librustc_query_system/dep_graph/README.md
index b9d91cd35a8..b9d91cd35a8 100644
--- a/src/librustc/dep_graph/README.md
+++ b/src/librustc_query_system/dep_graph/README.md
diff --git a/src/librustc/dep_graph/debug.rs b/src/librustc_query_system/dep_graph/debug.rs
index d44c54593a6..d44c54593a6 100644
--- a/src/librustc/dep_graph/debug.rs
+++ b/src/librustc_query_system/dep_graph/debug.rs
diff --git a/src/librustc_query_system/dep_graph/dep_node.rs b/src/librustc_query_system/dep_graph/dep_node.rs
new file mode 100644
index 00000000000..e3df9d5d04b
--- /dev/null
+++ b/src/librustc_query_system/dep_graph/dep_node.rs
@@ -0,0 +1,520 @@
+//! 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 could 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 crate::hir::map::DefPathHash;
+use crate::ich::{Fingerprint, StableHashingContext};
+use crate::mir;
+use crate::mir::interpret::{GlobalId, LitToConstInput};
+use crate::traits;
+use crate::traits::query::{
+    CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal,
+    CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal,
+    CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal,
+};
+use crate::ty::subst::SubstsRef;
+use crate::ty::{self, ParamEnvAnd, Ty, TyCtxt};
+
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX};
+use rustc_hir::HirId;
+use rustc_span::symbol::Symbol;
+use std::fmt;
+use std::hash::Hash;
+
+// 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! is_anon_attr {
+    (anon) => {
+        true
+    };
+    ($attr:ident) => {
+        false
+    };
+}
+
+macro_rules! is_eval_always_attr {
+    (eval_always) => {
+        true
+    };
+    ($attr:ident) => {
+        false
+    };
+}
+
+macro_rules! contains_anon_attr {
+    ($($attr:ident $(($($attr_args:tt)*))* ),*) => ({$(is_anon_attr!($attr) | )* false});
+}
+
+macro_rules! contains_eval_always_attr {
+    ($($attr:ident $(($($attr_args:tt)*))* ),*) => ({$(is_eval_always_attr!($attr) | )* false});
+}
+
+macro_rules! define_dep_nodes {
+    (<$tcx:tt>
+    $(
+        [$($attrs:tt)*]
+        $variant:ident $(( $tuple_arg_ty:ty $(,)? ))*
+      ,)*
+    ) => (
+        #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash,
+                 RustcEncodable, RustcDecodable)]
+        #[allow(non_camel_case_types)]
+        pub enum DepKind {
+            $($variant),*
+        }
+
+        impl DepKind {
+            #[allow(unreachable_code)]
+            pub fn can_reconstruct_query_key<$tcx>(&self) -> bool {
+                match *self {
+                    $(
+                        DepKind :: $variant => {
+                            if contains_anon_attr!($($attrs)*) {
+                                return false;
+                            }
+
+                            // tuple args
+                            $({
+                                return <$tuple_arg_ty as DepNodeParams>
+                                    ::CAN_RECONSTRUCT_QUERY_KEY;
+                            })*
+
+                            true
+                        }
+                    )*
+                }
+            }
+
+            pub fn is_anon(&self) -> bool {
+                match *self {
+                    $(
+                        DepKind :: $variant => { contains_anon_attr!($($attrs)*) }
+                    )*
+                }
+            }
+
+            pub fn is_eval_always(&self) -> bool {
+                match *self {
+                    $(
+                        DepKind :: $variant => { contains_eval_always_attr!($($attrs)*) }
+                    )*
+                }
+            }
+
+            #[allow(unreachable_code)]
+            pub fn has_params(&self) -> bool {
+                match *self {
+                    $(
+                        DepKind :: $variant => {
+                            // tuple args
+                            $({
+                                erase!($tuple_arg_ty);
+                                return true;
+                            })*
+
+                            false
+                        }
+                    )*
+                }
+            }
+        }
+
+        pub struct DepConstructor;
+
+        #[allow(non_camel_case_types)]
+        impl DepConstructor {
+            $(
+                #[inline(always)]
+                #[allow(unreachable_code, non_snake_case)]
+                pub fn $variant(_tcx: TyCtxt<'_>, $(arg: $tuple_arg_ty)*) -> DepNode {
+                    // tuple args
+                    $({
+                        erase!($tuple_arg_ty);
+                        let hash = DepNodeParams::to_fingerprint(&arg, _tcx);
+                        let dep_node = DepNode {
+                            kind: DepKind::$variant,
+                            hash
+                        };
+
+                        #[cfg(debug_assertions)]
+                        {
+                            if !dep_node.kind.can_reconstruct_query_key() &&
+                            (_tcx.sess.opts.debugging_opts.incremental_info ||
+                                _tcx.sess.opts.debugging_opts.query_dep_graph)
+                            {
+                                _tcx.dep_graph.register_dep_node_debug_str(dep_node, || {
+                                    arg.to_debug_str(_tcx)
+                                });
+                            }
+                        }
+
+                        return dep_node;
+                    })*
+
+                    DepNode {
+                        kind: DepKind::$variant,
+                        hash: Fingerprint::ZERO,
+                    }
+                }
+            )*
+        }
+
+        #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash,
+                 RustcEncodable, RustcDecodable)]
+        pub struct DepNode {
+            pub kind: DepKind,
+            pub hash: Fingerprint,
+        }
+
+        impl DepNode {
+            /// Construct a DepNode from the given DepKind and DefPathHash. This
+            /// method will assert that the given DepKind actually requires a
+            /// single DefId/DefPathHash parameter.
+            pub fn from_def_path_hash(def_path_hash: DefPathHash,
+                                      kind: DepKind)
+                                      -> DepNode {
+                debug_assert!(kind.can_reconstruct_query_key() && kind.has_params());
+                DepNode {
+                    kind,
+                    hash: def_path_hash.0,
+                }
+            }
+
+            /// Creates a new, parameterless DepNode. This method will assert
+            /// that the DepNode corresponding to the given DepKind actually
+            /// does not require any parameters.
+            pub fn new_no_params(kind: DepKind) -> DepNode {
+                debug_assert!(!kind.has_params());
+                DepNode {
+                    kind,
+                    hash: Fingerprint::ZERO,
+                }
+            }
+
+            /// Extracts 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.
+            pub fn extract_def_id(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
+                if self.kind.can_reconstruct_query_key() {
+                    let def_path_hash = DefPathHash(self.hash);
+                    tcx.def_path_hash_to_def_id.as_ref()?
+                        .get(&def_path_hash).cloned()
+                } else {
+                    None
+                }
+            }
+
+            /// Used in testing
+            pub fn from_label_string(label: &str,
+                                     def_path_hash: DefPathHash)
+                                     -> Result<DepNode, ()> {
+                let kind = match label {
+                    $(
+                        stringify!($variant) => DepKind::$variant,
+                    )*
+                    _ => return Err(()),
+                };
+
+                if !kind.can_reconstruct_query_key() {
+                    return Err(());
+                }
+
+                if kind.has_params() {
+                    Ok(DepNode::from_def_path_hash(def_path_hash, kind))
+                } else {
+                    Ok(DepNode::new_no_params(kind))
+                }
+            }
+
+            /// Used in testing
+            pub fn has_label_string(label: &str) -> bool {
+                match label {
+                    $(
+                        stringify!($variant) => true,
+                    )*
+                    _ => false,
+                }
+            }
+        }
+
+        /// Contains variant => str representations for constructing
+        /// DepNode groups for tests.
+        #[allow(dead_code, non_upper_case_globals)]
+        pub mod label_strs {
+           $(
+                pub const $variant: &str = stringify!($variant);
+            )*
+        }
+    );
+}
+
+impl fmt::Debug for DepNode {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{:?}", self.kind)?;
+
+        if !self.kind.has_params() && !self.kind.is_anon() {
+            return Ok(());
+        }
+
+        write!(f, "(")?;
+
+        crate::ty::tls::with_opt(|opt_tcx| {
+            if let Some(tcx) = opt_tcx {
+                if let Some(def_id) = self.extract_def_id(tcx) {
+                    write!(f, "{}", tcx.def_path_debug_str(def_id))?;
+                } else if let Some(ref s) = tcx.dep_graph.dep_node_debug_str(*self) {
+                    write!(f, "{}", s)?;
+                } else {
+                    write!(f, "{}", self.hash)?;
+                }
+            } else {
+                write!(f, "{}", self.hash)?;
+            }
+            Ok(())
+        })?;
+
+        write!(f, ")")
+    }
+}
+
+rustc_dep_node_append!([define_dep_nodes!][ <'tcx>
+    // We use this for most things when incr. comp. is turned off.
+    [] Null,
+
+    // Represents metadata from an extern crate.
+    [eval_always] CrateMetadata(CrateNum),
+
+    [anon] TraitSelect,
+
+    [] CompileCodegenUnit(Symbol),
+]);
+
+pub(crate) trait DepNodeParams<'tcx>: fmt::Debug + Sized {
+    const CAN_RECONSTRUCT_QUERY_KEY: bool;
+
+    /// This method turns the parameters of a DepNodeConstructor into an opaque
+    /// Fingerprint to be used in DepNode.
+    /// Not all DepNodeParams support being turned into a Fingerprint (they
+    /// don't need to if the corresponding DepNode is anonymous).
+    fn to_fingerprint(&self, _: TyCtxt<'tcx>) -> Fingerprint {
+        panic!("Not implemented. Accidentally called on anonymous node?")
+    }
+
+    fn to_debug_str(&self, _: TyCtxt<'tcx>) -> String {
+        format!("{:?}", self)
+    }
+
+    /// This method tries to recover the query key from the given `DepNode`,
+    /// something which is needed when forcing `DepNode`s during red-green
+    /// evaluation. The query system will only call this method if
+    /// `CAN_RECONSTRUCT_QUERY_KEY` is `true`.
+    /// It is always valid to return `None` here, in which case incremental
+    /// compilation will treat the query as having changed instead of forcing it.
+    fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self>;
+}
+
+impl<'tcx, T> DepNodeParams<'tcx> for T
+where
+    T: HashStable<StableHashingContext<'tcx>> + fmt::Debug,
+{
+    default const CAN_RECONSTRUCT_QUERY_KEY: bool = false;
+
+    default fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
+        let mut hcx = tcx.create_stable_hashing_context();
+        let mut hasher = StableHasher::new();
+
+        self.hash_stable(&mut hcx, &mut hasher);
+
+        hasher.finish()
+    }
+
+    default fn to_debug_str(&self, _: TyCtxt<'tcx>) -> String {
+        format!("{:?}", *self)
+    }
+
+    default fn recover(_: TyCtxt<'tcx>, _: &DepNode) -> Option<Self> {
+        None
+    }
+}
+
+impl<'tcx> DepNodeParams<'tcx> for DefId {
+    const CAN_RECONSTRUCT_QUERY_KEY: bool = true;
+
+    fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint {
+        tcx.def_path_hash(*self).0
+    }
+
+    fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
+        tcx.def_path_str(*self)
+    }
+
+    fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
+        dep_node.extract_def_id(tcx)
+    }
+}
+
+impl<'tcx> DepNodeParams<'tcx> for DefIndex {
+    const CAN_RECONSTRUCT_QUERY_KEY: bool = true;
+
+    fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint {
+        tcx.hir().definitions().def_path_hash(*self).0
+    }
+
+    fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
+        tcx.def_path_str(DefId::local(*self))
+    }
+
+    fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
+        dep_node.extract_def_id(tcx).map(|id| id.index)
+    }
+}
+
+impl<'tcx> DepNodeParams<'tcx> for CrateNum {
+    const CAN_RECONSTRUCT_QUERY_KEY: bool = true;
+
+    fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint {
+        let def_id = DefId { krate: *self, index: CRATE_DEF_INDEX };
+        tcx.def_path_hash(def_id).0
+    }
+
+    fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
+        tcx.crate_name(*self).to_string()
+    }
+
+    fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
+        dep_node.extract_def_id(tcx).map(|id| id.krate)
+    }
+}
+
+impl<'tcx> DepNodeParams<'tcx> for (DefId, DefId) {
+    const CAN_RECONSTRUCT_QUERY_KEY: bool = false;
+
+    // We actually would not need to specialize the implementation of this
+    // method but it's faster to combine the hashes than to instantiate a full
+    // hashing context and stable-hashing state.
+    fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint {
+        let (def_id_0, def_id_1) = *self;
+
+        let def_path_hash_0 = tcx.def_path_hash(def_id_0);
+        let def_path_hash_1 = tcx.def_path_hash(def_id_1);
+
+        def_path_hash_0.0.combine(def_path_hash_1.0)
+    }
+
+    fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
+        let (def_id_0, def_id_1) = *self;
+
+        format!("({}, {})", tcx.def_path_debug_str(def_id_0), tcx.def_path_debug_str(def_id_1))
+    }
+}
+
+impl<'tcx> DepNodeParams<'tcx> for HirId {
+    const CAN_RECONSTRUCT_QUERY_KEY: bool = false;
+
+    // We actually would not need to specialize the implementation of this
+    // method but it's faster to combine the hashes than to instantiate a full
+    // hashing context and stable-hashing state.
+    fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint {
+        let HirId { owner, local_id } = *self;
+
+        let def_path_hash = tcx.def_path_hash(DefId::local(owner));
+        let local_id = Fingerprint::from_smaller_hash(local_id.as_u32().into());
+
+        def_path_hash.0.combine(local_id)
+    }
+}
+
+/// A "work product" corresponds to a `.o` (or other) file that we
+/// save in between runs. These IDs do not have a `DefId` but rather
+/// 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,
+    Copy,
+    Debug,
+    PartialEq,
+    Eq,
+    PartialOrd,
+    Ord,
+    Hash,
+    RustcEncodable,
+    RustcDecodable,
+    HashStable
+)]
+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 { hash: hasher.finish() }
+    }
+
+    pub fn from_fingerprint(fingerprint: Fingerprint) -> WorkProductId {
+        WorkProductId { hash: fingerprint }
+    }
+}
diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc_query_system/dep_graph/graph.rs
index 36edf0f0fc2..36edf0f0fc2 100644
--- a/src/librustc/dep_graph/graph.rs
+++ b/src/librustc_query_system/dep_graph/graph.rs
diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc_query_system/dep_graph/mod.rs
index 1fbd90743f4..1fbd90743f4 100644
--- a/src/librustc/dep_graph/mod.rs
+++ b/src/librustc_query_system/dep_graph/mod.rs
diff --git a/src/librustc/dep_graph/prev.rs b/src/librustc_query_system/dep_graph/prev.rs
index fbc8f7bc997..fbc8f7bc997 100644
--- a/src/librustc/dep_graph/prev.rs
+++ b/src/librustc_query_system/dep_graph/prev.rs
diff --git a/src/librustc/dep_graph/query.rs b/src/librustc_query_system/dep_graph/query.rs
index c71c11ed0eb..c71c11ed0eb 100644
--- a/src/librustc/dep_graph/query.rs
+++ b/src/librustc_query_system/dep_graph/query.rs
diff --git a/src/librustc/dep_graph/safe.rs b/src/librustc_query_system/dep_graph/safe.rs
index 74e32867cde..74e32867cde 100644
--- a/src/librustc/dep_graph/safe.rs
+++ b/src/librustc_query_system/dep_graph/safe.rs
diff --git a/src/librustc/dep_graph/serialized.rs b/src/librustc_query_system/dep_graph/serialized.rs
index 45ef52dbf39..45ef52dbf39 100644
--- a/src/librustc/dep_graph/serialized.rs
+++ b/src/librustc_query_system/dep_graph/serialized.rs