rustc_middle/dep_graph/
dep_node.rs

1use rustc_data_structures::fingerprint::Fingerprint;
2use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId, LocalModDefId, ModDefId};
3use rustc_hir::definitions::DefPathHash;
4use rustc_hir::{HirId, ItemLocalId, OwnerId};
5pub use rustc_query_system::dep_graph::DepNode;
6use rustc_query_system::dep_graph::FingerprintStyle;
7pub use rustc_query_system::dep_graph::dep_node::DepKind;
8pub(crate) use rustc_query_system::dep_graph::{DepContext, DepNodeParams};
9use rustc_span::Symbol;
10
11use crate::mir::mono::MonoItem;
12use crate::ty::TyCtxt;
13
14macro_rules! define_dep_nodes {
15    (
16     $($(#[$attr:meta])*
17        [$($modifiers:tt)*] fn $variant:ident($($K:tt)*) -> $V:ty,)*) => {
18
19        #[macro_export]
20        macro_rules! make_dep_kind_array {
21            ($mod:ident) => {[ $($mod::$variant()),* ]};
22        }
23
24        /// This enum serves as an index into arrays built by `make_dep_kind_array`.
25        // This enum has more than u8::MAX variants so we need some kind of multi-byte
26        // encoding. The derived Encodable/Decodable uses leb128 encoding which is
27        // dense when only considering this enum. But DepKind is encoded in a larger
28        // struct, and there we can take advantage of the unused bits in the u16.
29        #[allow(non_camel_case_types)]
30        #[repr(u16)] // Must be kept in sync with the inner type of `DepKind`.
31        enum DepKindDefs {
32            $( $( #[$attr] )* $variant),*
33        }
34
35        #[allow(non_upper_case_globals)]
36        pub mod dep_kinds {
37            use super::*;
38
39            $(
40                // The `as u16` cast must be kept in sync with the inner type of `DepKind`.
41                pub const $variant: DepKind = DepKind::new(DepKindDefs::$variant as u16);
42            )*
43        }
44
45        // This checks that the discriminants of the variants have been assigned consecutively
46        // from 0 so that they can be used as a dense index.
47        pub(crate) const DEP_KIND_VARIANTS: u16 = {
48            let deps = &[$(dep_kinds::$variant,)*];
49            let mut i = 0;
50            while i < deps.len() {
51                if i != deps[i].as_usize() {
52                    panic!();
53                }
54                i += 1;
55            }
56            deps.len() as u16
57        };
58
59        pub(super) fn dep_kind_from_label_string(label: &str) -> Result<DepKind, ()> {
60            match label {
61                $(stringify!($variant) => Ok(dep_kinds::$variant),)*
62                _ => Err(()),
63            }
64        }
65
66        /// Contains variant => str representations for constructing
67        /// DepNode groups for tests.
68        #[allow(dead_code, non_upper_case_globals)]
69        pub mod label_strs {
70           $(
71                pub const $variant: &str = stringify!($variant);
72            )*
73        }
74    };
75}
76
77rustc_query_append!(define_dep_nodes![
78    /// We use this for most things when incr. comp. is turned off.
79    [] fn Null() -> (),
80    /// We use this to create a forever-red node.
81    [] fn Red() -> (),
82    [] fn SideEffect() -> (),
83    [] fn TraitSelect() -> (),
84    [] fn CompileCodegenUnit() -> (),
85    [] fn CompileMonoItem() -> (),
86]);
87
88// WARNING: `construct` is generic and does not know that `CompileCodegenUnit` takes `Symbol`s as keys.
89// Be very careful changing this type signature!
90pub(crate) fn make_compile_codegen_unit(tcx: TyCtxt<'_>, name: Symbol) -> DepNode {
91    DepNode::construct(tcx, dep_kinds::CompileCodegenUnit, &name)
92}
93
94// WARNING: `construct` is generic and does not know that `CompileMonoItem` takes `MonoItem`s as keys.
95// Be very careful changing this type signature!
96pub(crate) fn make_compile_mono_item<'tcx>(
97    tcx: TyCtxt<'tcx>,
98    mono_item: &MonoItem<'tcx>,
99) -> DepNode {
100    DepNode::construct(tcx, dep_kinds::CompileMonoItem, mono_item)
101}
102
103pub trait DepNodeExt: Sized {
104    fn extract_def_id(&self, tcx: TyCtxt<'_>) -> Option<DefId>;
105
106    fn from_label_string(
107        tcx: TyCtxt<'_>,
108        label: &str,
109        def_path_hash: DefPathHash,
110    ) -> Result<Self, ()>;
111
112    fn has_label_string(label: &str) -> bool;
113}
114
115impl DepNodeExt for DepNode {
116    /// Extracts the DefId corresponding to this DepNode. This will work
117    /// if two conditions are met:
118    ///
119    /// 1. The Fingerprint of the DepNode actually is a DefPathHash, and
120    /// 2. the item that the DefPath refers to exists in the current tcx.
121    ///
122    /// Condition (1) is determined by the DepKind variant of the
123    /// DepNode. Condition (2) might not be fulfilled if a DepNode
124    /// refers to something from the previous compilation session that
125    /// has been removed.
126    fn extract_def_id(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
127        if tcx.fingerprint_style(self.kind) == FingerprintStyle::DefPathHash {
128            tcx.def_path_hash_to_def_id(DefPathHash(self.hash.into()))
129        } else {
130            None
131        }
132    }
133
134    /// Used in testing
135    fn from_label_string(
136        tcx: TyCtxt<'_>,
137        label: &str,
138        def_path_hash: DefPathHash,
139    ) -> Result<DepNode, ()> {
140        let kind = dep_kind_from_label_string(label)?;
141
142        match tcx.fingerprint_style(kind) {
143            FingerprintStyle::Opaque | FingerprintStyle::HirId => Err(()),
144            FingerprintStyle::Unit => Ok(DepNode::new_no_params(tcx, kind)),
145            FingerprintStyle::DefPathHash => {
146                Ok(DepNode::from_def_path_hash(tcx, def_path_hash, kind))
147            }
148        }
149    }
150
151    /// Used in testing
152    fn has_label_string(label: &str) -> bool {
153        dep_kind_from_label_string(label).is_ok()
154    }
155}
156
157impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for () {
158    #[inline(always)]
159    fn fingerprint_style() -> FingerprintStyle {
160        FingerprintStyle::Unit
161    }
162
163    #[inline(always)]
164    fn to_fingerprint(&self, _: TyCtxt<'tcx>) -> Fingerprint {
165        Fingerprint::ZERO
166    }
167
168    #[inline(always)]
169    fn recover(_: TyCtxt<'tcx>, _: &DepNode) -> Option<Self> {
170        Some(())
171    }
172}
173
174impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for DefId {
175    #[inline(always)]
176    fn fingerprint_style() -> FingerprintStyle {
177        FingerprintStyle::DefPathHash
178    }
179
180    #[inline(always)]
181    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
182        tcx.def_path_hash(*self).0
183    }
184
185    #[inline(always)]
186    fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
187        tcx.def_path_str(*self)
188    }
189
190    #[inline(always)]
191    fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
192        dep_node.extract_def_id(tcx)
193    }
194}
195
196impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for LocalDefId {
197    #[inline(always)]
198    fn fingerprint_style() -> FingerprintStyle {
199        FingerprintStyle::DefPathHash
200    }
201
202    #[inline(always)]
203    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
204        self.to_def_id().to_fingerprint(tcx)
205    }
206
207    #[inline(always)]
208    fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
209        self.to_def_id().to_debug_str(tcx)
210    }
211
212    #[inline(always)]
213    fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
214        dep_node.extract_def_id(tcx).map(|id| id.expect_local())
215    }
216}
217
218impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for OwnerId {
219    #[inline(always)]
220    fn fingerprint_style() -> FingerprintStyle {
221        FingerprintStyle::DefPathHash
222    }
223
224    #[inline(always)]
225    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
226        self.to_def_id().to_fingerprint(tcx)
227    }
228
229    #[inline(always)]
230    fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
231        self.to_def_id().to_debug_str(tcx)
232    }
233
234    #[inline(always)]
235    fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
236        dep_node.extract_def_id(tcx).map(|id| OwnerId { def_id: id.expect_local() })
237    }
238}
239
240impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for CrateNum {
241    #[inline(always)]
242    fn fingerprint_style() -> FingerprintStyle {
243        FingerprintStyle::DefPathHash
244    }
245
246    #[inline(always)]
247    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
248        let def_id = self.as_def_id();
249        def_id.to_fingerprint(tcx)
250    }
251
252    #[inline(always)]
253    fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
254        tcx.crate_name(*self).to_string()
255    }
256
257    #[inline(always)]
258    fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
259        dep_node.extract_def_id(tcx).map(|id| id.krate)
260    }
261}
262
263impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for (DefId, DefId) {
264    #[inline(always)]
265    fn fingerprint_style() -> FingerprintStyle {
266        FingerprintStyle::Opaque
267    }
268
269    // We actually would not need to specialize the implementation of this
270    // method but it's faster to combine the hashes than to instantiate a full
271    // hashing context and stable-hashing state.
272    #[inline(always)]
273    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
274        let (def_id_0, def_id_1) = *self;
275
276        let def_path_hash_0 = tcx.def_path_hash(def_id_0);
277        let def_path_hash_1 = tcx.def_path_hash(def_id_1);
278
279        def_path_hash_0.0.combine(def_path_hash_1.0)
280    }
281
282    #[inline(always)]
283    fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
284        let (def_id_0, def_id_1) = *self;
285
286        format!("({}, {})", tcx.def_path_debug_str(def_id_0), tcx.def_path_debug_str(def_id_1))
287    }
288}
289
290impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for HirId {
291    #[inline(always)]
292    fn fingerprint_style() -> FingerprintStyle {
293        FingerprintStyle::HirId
294    }
295
296    // We actually would not need to specialize the implementation of this
297    // method but it's faster to combine the hashes than to instantiate a full
298    // hashing context and stable-hashing state.
299    #[inline(always)]
300    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
301        let HirId { owner, local_id } = *self;
302        let def_path_hash = tcx.def_path_hash(owner.to_def_id());
303        Fingerprint::new(
304            // `owner` is local, so is completely defined by the local hash
305            def_path_hash.local_hash(),
306            local_id.as_u32() as u64,
307        )
308    }
309
310    #[inline(always)]
311    fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
312        let HirId { owner, local_id } = *self;
313        format!("{}.{}", tcx.def_path_str(owner), local_id.as_u32())
314    }
315
316    #[inline(always)]
317    fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
318        if tcx.fingerprint_style(dep_node.kind) == FingerprintStyle::HirId {
319            let (local_hash, local_id) = Fingerprint::from(dep_node.hash).split();
320            let def_path_hash = DefPathHash::new(tcx.stable_crate_id(LOCAL_CRATE), local_hash);
321            let def_id = tcx.def_path_hash_to_def_id(def_path_hash)?.expect_local();
322            let local_id = local_id
323                .as_u64()
324                .try_into()
325                .unwrap_or_else(|_| panic!("local id should be u32, found {local_id:?}"));
326            Some(HirId { owner: OwnerId { def_id }, local_id: ItemLocalId::from_u32(local_id) })
327        } else {
328            None
329        }
330    }
331}
332
333impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for ModDefId {
334    #[inline(always)]
335    fn fingerprint_style() -> FingerprintStyle {
336        FingerprintStyle::DefPathHash
337    }
338
339    #[inline(always)]
340    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
341        self.to_def_id().to_fingerprint(tcx)
342    }
343
344    #[inline(always)]
345    fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
346        self.to_def_id().to_debug_str(tcx)
347    }
348
349    #[inline(always)]
350    fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
351        DefId::recover(tcx, dep_node).map(ModDefId::new_unchecked)
352    }
353}
354
355impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for LocalModDefId {
356    #[inline(always)]
357    fn fingerprint_style() -> FingerprintStyle {
358        FingerprintStyle::DefPathHash
359    }
360
361    #[inline(always)]
362    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
363        self.to_def_id().to_fingerprint(tcx)
364    }
365
366    #[inline(always)]
367    fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
368        self.to_def_id().to_debug_str(tcx)
369    }
370
371    #[inline(always)]
372    fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
373        LocalDefId::recover(tcx, dep_node).map(LocalModDefId::new_unchecked)
374    }
375}