| use rustc_data_structures::fingerprint::Fingerprint; |
| use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId, LocalModDefId, ModDefId}; |
| use rustc_hir::definitions::DefPathHash; |
| use rustc_hir::{HirId, ItemLocalId, OwnerId}; |
| pub use rustc_query_system::dep_graph::DepNode; |
| use rustc_query_system::dep_graph::FingerprintStyle; |
| pub use rustc_query_system::dep_graph::dep_node::DepKind; |
| pub(crate) use rustc_query_system::dep_graph::{DepContext, DepNodeParams}; |
| use rustc_span::Symbol; |
| |
| use crate::mir::mono::MonoItem; |
| use crate::ty::TyCtxt; |
| |
| macro_rules! define_dep_nodes { |
| ( |
| $( |
| $(#[$attr:meta])* |
| [$($modifiers:tt)*] fn $variant:ident($($K:tt)*) -> $V:ty, |
| )* |
| ) => { |
| |
| #[macro_export] |
| macro_rules! make_dep_kind_array { |
| ($mod:ident) => {[ $($mod::$variant()),* ]}; |
| } |
| |
| #[macro_export] |
| macro_rules! make_dep_kind_name_array { |
| ($mod:ident) => { |
| vec! { |
| $(*$mod::$variant().name),* |
| } |
| }; |
| } |
| |
| /// This enum serves as an index into arrays built by `make_dep_kind_array`. |
| // This enum has more than u8::MAX variants so we need some kind of multi-byte |
| // encoding. The derived Encodable/Decodable uses leb128 encoding which is |
| // dense when only considering this enum. But DepKind is encoded in a larger |
| // struct, and there we can take advantage of the unused bits in the u16. |
| #[allow(non_camel_case_types)] |
| #[repr(u16)] // Must be kept in sync with the inner type of `DepKind`. |
| enum DepKindDefs { |
| $( $( #[$attr] )* $variant),* |
| } |
| |
| #[allow(non_upper_case_globals)] |
| pub mod dep_kinds { |
| use super::*; |
| |
| $( |
| // The `as u16` cast must be kept in sync with the inner type of `DepKind`. |
| pub const $variant: DepKind = DepKind::new(DepKindDefs::$variant as u16); |
| )* |
| } |
| |
| // This checks that the discriminants of the variants have been assigned consecutively |
| // from 0 so that they can be used as a dense index. |
| pub(crate) const DEP_KIND_VARIANTS: u16 = { |
| let deps = &[$(dep_kinds::$variant,)*]; |
| let mut i = 0; |
| while i < deps.len() { |
| if i != deps[i].as_usize() { |
| panic!(); |
| } |
| i += 1; |
| } |
| deps.len() as u16 |
| }; |
| |
| pub(super) fn dep_kind_from_label_string(label: &str) -> Result<DepKind, ()> { |
| match label { |
| $(stringify!($variant) => Ok(dep_kinds::$variant),)* |
| _ => Err(()), |
| } |
| } |
| |
| /// 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); |
| )* |
| } |
| }; |
| } |
| |
| // Create various data structures for each query, and also for a few things |
| // that aren't queries. |
| rustc_with_all_queries!(define_dep_nodes![ |
| /// We use this for most things when incr. comp. is turned off. |
| [] fn Null() -> (), |
| /// We use this to create a forever-red node. |
| [] fn Red() -> (), |
| [] fn SideEffect() -> (), |
| [] fn AnonZeroDeps() -> (), |
| [] fn TraitSelect() -> (), |
| [] fn CompileCodegenUnit() -> (), |
| [] fn CompileMonoItem() -> (), |
| [] fn Metadata() -> (), |
| ]); |
| |
| // WARNING: `construct` is generic and does not know that `CompileCodegenUnit` takes `Symbol`s as keys. |
| // Be very careful changing this type signature! |
| pub(crate) fn make_compile_codegen_unit(tcx: TyCtxt<'_>, name: Symbol) -> DepNode { |
| DepNode::construct(tcx, dep_kinds::CompileCodegenUnit, &name) |
| } |
| |
| // WARNING: `construct` is generic and does not know that `CompileMonoItem` takes `MonoItem`s as keys. |
| // Be very careful changing this type signature! |
| pub(crate) fn make_compile_mono_item<'tcx>( |
| tcx: TyCtxt<'tcx>, |
| mono_item: &MonoItem<'tcx>, |
| ) -> DepNode { |
| DepNode::construct(tcx, dep_kinds::CompileMonoItem, mono_item) |
| } |
| |
| // WARNING: `construct` is generic and does not know that `Metadata` takes `()`s as keys. |
| // Be very careful changing this type signature! |
| pub(crate) fn make_metadata(tcx: TyCtxt<'_>) -> DepNode { |
| DepNode::construct(tcx, dep_kinds::Metadata, &()) |
| } |
| |
| pub trait DepNodeExt: Sized { |
| fn extract_def_id(&self, tcx: TyCtxt<'_>) -> Option<DefId>; |
| |
| fn from_label_string( |
| tcx: TyCtxt<'_>, |
| label: &str, |
| def_path_hash: DefPathHash, |
| ) -> Result<Self, ()>; |
| |
| fn has_label_string(label: &str) -> bool; |
| } |
| |
| impl DepNodeExt for DepNode { |
| /// 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. |
| fn extract_def_id(&self, tcx: TyCtxt<'_>) -> Option<DefId> { |
| if tcx.fingerprint_style(self.kind) == FingerprintStyle::DefPathHash { |
| tcx.def_path_hash_to_def_id(DefPathHash(self.hash.into())) |
| } else { |
| None |
| } |
| } |
| |
| /// Used in testing |
| fn from_label_string( |
| tcx: TyCtxt<'_>, |
| label: &str, |
| def_path_hash: DefPathHash, |
| ) -> Result<DepNode, ()> { |
| let kind = dep_kind_from_label_string(label)?; |
| |
| match tcx.fingerprint_style(kind) { |
| FingerprintStyle::Opaque | FingerprintStyle::HirId => Err(()), |
| FingerprintStyle::Unit => Ok(DepNode::new_no_params(tcx, kind)), |
| FingerprintStyle::DefPathHash => { |
| Ok(DepNode::from_def_path_hash(tcx, def_path_hash, kind)) |
| } |
| } |
| } |
| |
| /// Used in testing |
| fn has_label_string(label: &str) -> bool { |
| dep_kind_from_label_string(label).is_ok() |
| } |
| } |
| |
| impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for () { |
| #[inline(always)] |
| fn fingerprint_style() -> FingerprintStyle { |
| FingerprintStyle::Unit |
| } |
| |
| #[inline(always)] |
| fn to_fingerprint(&self, _: TyCtxt<'tcx>) -> Fingerprint { |
| Fingerprint::ZERO |
| } |
| |
| #[inline(always)] |
| fn recover(_: TyCtxt<'tcx>, _: &DepNode) -> Option<Self> { |
| Some(()) |
| } |
| } |
| |
| impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for DefId { |
| #[inline(always)] |
| fn fingerprint_style() -> FingerprintStyle { |
| FingerprintStyle::DefPathHash |
| } |
| |
| #[inline(always)] |
| fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { |
| tcx.def_path_hash(*self).0 |
| } |
| |
| #[inline(always)] |
| fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String { |
| tcx.def_path_str(*self) |
| } |
| |
| #[inline(always)] |
| fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> { |
| dep_node.extract_def_id(tcx) |
| } |
| } |
| |
| impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for LocalDefId { |
| #[inline(always)] |
| fn fingerprint_style() -> FingerprintStyle { |
| FingerprintStyle::DefPathHash |
| } |
| |
| #[inline(always)] |
| fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { |
| self.to_def_id().to_fingerprint(tcx) |
| } |
| |
| #[inline(always)] |
| fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String { |
| self.to_def_id().to_debug_str(tcx) |
| } |
| |
| #[inline(always)] |
| fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> { |
| dep_node.extract_def_id(tcx).map(|id| id.expect_local()) |
| } |
| } |
| |
| impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for OwnerId { |
| #[inline(always)] |
| fn fingerprint_style() -> FingerprintStyle { |
| FingerprintStyle::DefPathHash |
| } |
| |
| #[inline(always)] |
| fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { |
| self.to_def_id().to_fingerprint(tcx) |
| } |
| |
| #[inline(always)] |
| fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String { |
| self.to_def_id().to_debug_str(tcx) |
| } |
| |
| #[inline(always)] |
| fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> { |
| dep_node.extract_def_id(tcx).map(|id| OwnerId { def_id: id.expect_local() }) |
| } |
| } |
| |
| impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for CrateNum { |
| #[inline(always)] |
| fn fingerprint_style() -> FingerprintStyle { |
| FingerprintStyle::DefPathHash |
| } |
| |
| #[inline(always)] |
| fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { |
| let def_id = self.as_def_id(); |
| def_id.to_fingerprint(tcx) |
| } |
| |
| #[inline(always)] |
| fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String { |
| tcx.crate_name(*self).to_string() |
| } |
| |
| #[inline(always)] |
| fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> { |
| dep_node.extract_def_id(tcx).map(|id| id.krate) |
| } |
| } |
| |
| impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for (DefId, DefId) { |
| #[inline(always)] |
| fn fingerprint_style() -> FingerprintStyle { |
| FingerprintStyle::Opaque |
| } |
| |
| // 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. |
| #[inline(always)] |
| fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> 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) |
| } |
| |
| #[inline(always)] |
| 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<TyCtxt<'tcx>> for HirId { |
| #[inline(always)] |
| fn fingerprint_style() -> FingerprintStyle { |
| FingerprintStyle::HirId |
| } |
| |
| // 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. |
| #[inline(always)] |
| fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { |
| let HirId { owner, local_id } = *self; |
| let def_path_hash = tcx.def_path_hash(owner.to_def_id()); |
| Fingerprint::new( |
| // `owner` is local, so is completely defined by the local hash |
| def_path_hash.local_hash(), |
| local_id.as_u32() as u64, |
| ) |
| } |
| |
| #[inline(always)] |
| fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String { |
| let HirId { owner, local_id } = *self; |
| format!("{}.{}", tcx.def_path_str(owner), local_id.as_u32()) |
| } |
| |
| #[inline(always)] |
| fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> { |
| if tcx.fingerprint_style(dep_node.kind) == FingerprintStyle::HirId { |
| let (local_hash, local_id) = Fingerprint::from(dep_node.hash).split(); |
| let def_path_hash = DefPathHash::new(tcx.stable_crate_id(LOCAL_CRATE), local_hash); |
| let def_id = tcx.def_path_hash_to_def_id(def_path_hash)?.expect_local(); |
| let local_id = local_id |
| .as_u64() |
| .try_into() |
| .unwrap_or_else(|_| panic!("local id should be u32, found {local_id:?}")); |
| Some(HirId { owner: OwnerId { def_id }, local_id: ItemLocalId::from_u32(local_id) }) |
| } else { |
| None |
| } |
| } |
| } |
| |
| impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for ModDefId { |
| #[inline(always)] |
| fn fingerprint_style() -> FingerprintStyle { |
| FingerprintStyle::DefPathHash |
| } |
| |
| #[inline(always)] |
| fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { |
| self.to_def_id().to_fingerprint(tcx) |
| } |
| |
| #[inline(always)] |
| fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String { |
| self.to_def_id().to_debug_str(tcx) |
| } |
| |
| #[inline(always)] |
| fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> { |
| DefId::recover(tcx, dep_node).map(ModDefId::new_unchecked) |
| } |
| } |
| |
| impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for LocalModDefId { |
| #[inline(always)] |
| fn fingerprint_style() -> FingerprintStyle { |
| FingerprintStyle::DefPathHash |
| } |
| |
| #[inline(always)] |
| fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { |
| self.to_def_id().to_fingerprint(tcx) |
| } |
| |
| #[inline(always)] |
| fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String { |
| self.to_def_id().to_debug_str(tcx) |
| } |
| |
| #[inline(always)] |
| fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> { |
| LocalDefId::recover(tcx, dep_node).map(LocalModDefId::new_unchecked) |
| } |
| } |