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 TraitSelect() -> (),
83    [] fn CompileCodegenUnit() -> (),
84    [] fn CompileMonoItem() -> (),
85]);
86
87// WARNING: `construct` is generic and does not know that `CompileCodegenUnit` takes `Symbol`s as keys.
88// Be very careful changing this type signature!
89pub(crate) fn make_compile_codegen_unit(tcx: TyCtxt<'_>, name: Symbol) -> DepNode {
90    DepNode::construct(tcx, dep_kinds::CompileCodegenUnit, &name)
91}
92
93// WARNING: `construct` is generic and does not know that `CompileMonoItem` takes `MonoItem`s as keys.
94// Be very careful changing this type signature!
95pub(crate) fn make_compile_mono_item<'tcx>(
96    tcx: TyCtxt<'tcx>,
97    mono_item: &MonoItem<'tcx>,
98) -> DepNode {
99    DepNode::construct(tcx, dep_kinds::CompileMonoItem, mono_item)
100}
101
102pub trait DepNodeExt: Sized {
103    fn extract_def_id(&self, tcx: TyCtxt<'_>) -> Option<DefId>;
104
105    fn from_label_string(
106        tcx: TyCtxt<'_>,
107        label: &str,
108        def_path_hash: DefPathHash,
109    ) -> Result<Self, ()>;
110
111    fn has_label_string(label: &str) -> bool;
112}
113
114impl DepNodeExt for DepNode {
115    /// Extracts the DefId corresponding to this DepNode. This will work
116    /// if two conditions are met:
117    ///
118    /// 1. The Fingerprint of the DepNode actually is a DefPathHash, and
119    /// 2. the item that the DefPath refers to exists in the current tcx.
120    ///
121    /// Condition (1) is determined by the DepKind variant of the
122    /// DepNode. Condition (2) might not be fulfilled if a DepNode
123    /// refers to something from the previous compilation session that
124    /// has been removed.
125    fn extract_def_id(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
126        if tcx.fingerprint_style(self.kind) == FingerprintStyle::DefPathHash {
127            tcx.def_path_hash_to_def_id(DefPathHash(self.hash.into()))
128        } else {
129            None
130        }
131    }
132
133    /// Used in testing
134    fn from_label_string(
135        tcx: TyCtxt<'_>,
136        label: &str,
137        def_path_hash: DefPathHash,
138    ) -> Result<DepNode, ()> {
139        let kind = dep_kind_from_label_string(label)?;
140
141        match tcx.fingerprint_style(kind) {
142            FingerprintStyle::Opaque | FingerprintStyle::HirId => Err(()),
143            FingerprintStyle::Unit => Ok(DepNode::new_no_params(tcx, kind)),
144            FingerprintStyle::DefPathHash => {
145                Ok(DepNode::from_def_path_hash(tcx, def_path_hash, kind))
146            }
147        }
148    }
149
150    /// Used in testing
151    fn has_label_string(label: &str) -> bool {
152        dep_kind_from_label_string(label).is_ok()
153    }
154}
155
156impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for () {
157    #[inline(always)]
158    fn fingerprint_style() -> FingerprintStyle {
159        FingerprintStyle::Unit
160    }
161
162    #[inline(always)]
163    fn to_fingerprint(&self, _: TyCtxt<'tcx>) -> Fingerprint {
164        Fingerprint::ZERO
165    }
166
167    #[inline(always)]
168    fn recover(_: TyCtxt<'tcx>, _: &DepNode) -> Option<Self> {
169        Some(())
170    }
171}
172
173impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for DefId {
174    #[inline(always)]
175    fn fingerprint_style() -> FingerprintStyle {
176        FingerprintStyle::DefPathHash
177    }
178
179    #[inline(always)]
180    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
181        tcx.def_path_hash(*self).0
182    }
183
184    #[inline(always)]
185    fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
186        tcx.def_path_str(*self)
187    }
188
189    #[inline(always)]
190    fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
191        dep_node.extract_def_id(tcx)
192    }
193}
194
195impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for LocalDefId {
196    #[inline(always)]
197    fn fingerprint_style() -> FingerprintStyle {
198        FingerprintStyle::DefPathHash
199    }
200
201    #[inline(always)]
202    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
203        self.to_def_id().to_fingerprint(tcx)
204    }
205
206    #[inline(always)]
207    fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
208        self.to_def_id().to_debug_str(tcx)
209    }
210
211    #[inline(always)]
212    fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
213        dep_node.extract_def_id(tcx).map(|id| id.expect_local())
214    }
215}
216
217impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for OwnerId {
218    #[inline(always)]
219    fn fingerprint_style() -> FingerprintStyle {
220        FingerprintStyle::DefPathHash
221    }
222
223    #[inline(always)]
224    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
225        self.to_def_id().to_fingerprint(tcx)
226    }
227
228    #[inline(always)]
229    fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
230        self.to_def_id().to_debug_str(tcx)
231    }
232
233    #[inline(always)]
234    fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
235        dep_node.extract_def_id(tcx).map(|id| OwnerId { def_id: id.expect_local() })
236    }
237}
238
239impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for CrateNum {
240    #[inline(always)]
241    fn fingerprint_style() -> FingerprintStyle {
242        FingerprintStyle::DefPathHash
243    }
244
245    #[inline(always)]
246    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
247        let def_id = self.as_def_id();
248        def_id.to_fingerprint(tcx)
249    }
250
251    #[inline(always)]
252    fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
253        tcx.crate_name(*self).to_string()
254    }
255
256    #[inline(always)]
257    fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
258        dep_node.extract_def_id(tcx).map(|id| id.krate)
259    }
260}
261
262impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for (DefId, DefId) {
263    #[inline(always)]
264    fn fingerprint_style() -> FingerprintStyle {
265        FingerprintStyle::Opaque
266    }
267
268    // We actually would not need to specialize the implementation of this
269    // method but it's faster to combine the hashes than to instantiate a full
270    // hashing context and stable-hashing state.
271    #[inline(always)]
272    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
273        let (def_id_0, def_id_1) = *self;
274
275        let def_path_hash_0 = tcx.def_path_hash(def_id_0);
276        let def_path_hash_1 = tcx.def_path_hash(def_id_1);
277
278        def_path_hash_0.0.combine(def_path_hash_1.0)
279    }
280
281    #[inline(always)]
282    fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
283        let (def_id_0, def_id_1) = *self;
284
285        format!("({}, {})", tcx.def_path_debug_str(def_id_0), tcx.def_path_debug_str(def_id_1))
286    }
287}
288
289impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for HirId {
290    #[inline(always)]
291    fn fingerprint_style() -> FingerprintStyle {
292        FingerprintStyle::HirId
293    }
294
295    // We actually would not need to specialize the implementation of this
296    // method but it's faster to combine the hashes than to instantiate a full
297    // hashing context and stable-hashing state.
298    #[inline(always)]
299    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
300        let HirId { owner, local_id } = *self;
301        let def_path_hash = tcx.def_path_hash(owner.to_def_id());
302        Fingerprint::new(
303            // `owner` is local, so is completely defined by the local hash
304            def_path_hash.local_hash(),
305            local_id.as_u32() as u64,
306        )
307    }
308
309    #[inline(always)]
310    fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
311        let HirId { owner, local_id } = *self;
312        format!("{}.{}", tcx.def_path_str(owner), local_id.as_u32())
313    }
314
315    #[inline(always)]
316    fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
317        if tcx.fingerprint_style(dep_node.kind) == FingerprintStyle::HirId {
318            let (local_hash, local_id) = Fingerprint::from(dep_node.hash).split();
319            let def_path_hash = DefPathHash::new(tcx.stable_crate_id(LOCAL_CRATE), local_hash);
320            let def_id = tcx.def_path_hash_to_def_id(def_path_hash)?.expect_local();
321            let local_id = local_id
322                .as_u64()
323                .try_into()
324                .unwrap_or_else(|_| panic!("local id should be u32, found {local_id:?}"));
325            Some(HirId { owner: OwnerId { def_id }, local_id: ItemLocalId::from_u32(local_id) })
326        } else {
327            None
328        }
329    }
330}
331
332impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for ModDefId {
333    #[inline(always)]
334    fn fingerprint_style() -> FingerprintStyle {
335        FingerprintStyle::DefPathHash
336    }
337
338    #[inline(always)]
339    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
340        self.to_def_id().to_fingerprint(tcx)
341    }
342
343    #[inline(always)]
344    fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
345        self.to_def_id().to_debug_str(tcx)
346    }
347
348    #[inline(always)]
349    fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
350        DefId::recover(tcx, dep_node).map(ModDefId::new_unchecked)
351    }
352}
353
354impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for LocalModDefId {
355    #[inline(always)]
356    fn fingerprint_style() -> FingerprintStyle {
357        FingerprintStyle::DefPathHash
358    }
359
360    #[inline(always)]
361    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
362        self.to_def_id().to_fingerprint(tcx)
363    }
364
365    #[inline(always)]
366    fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
367        self.to_def_id().to_debug_str(tcx)
368    }
369
370    #[inline(always)]
371    fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
372        LocalDefId::recover(tcx, dep_node).map(LocalModDefId::new_unchecked)
373    }
374}