Skip to main content

rustc_middle/dep_graph/
dep_node_key.rs

1use std::fmt::Debug;
2
3use rustc_data_structures::fingerprint::Fingerprint;
4use rustc_data_structures::stable_hasher::{StableHash, StableHasher};
5use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId, LocalModDefId, ModDefId};
6use rustc_hir::definitions::DefPathHash;
7use rustc_hir::{HirId, ItemLocalId, OwnerId};
8
9use crate::dep_graph::{DepNode, KeyFingerprintStyle};
10use crate::ty::TyCtxt;
11
12/// Trait for query keys as seen by dependency-node tracking.
13pub trait DepNodeKey<'tcx>: Debug + Sized {
14    fn key_fingerprint_style() -> KeyFingerprintStyle;
15
16    /// This method turns a query key into an opaque `Fingerprint` to be used
17    /// in `DepNode`.
18    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint;
19
20    /// This method tries to recover the query key from the given `DepNode`,
21    /// something which is needed when forcing `DepNode`s during red-green
22    /// evaluation. The query system will only call this method if
23    /// `fingerprint_style()` is not `FingerprintStyle::Opaque`.
24    /// It is always valid to return `None` here, in which case incremental
25    /// compilation will treat the query as having changed instead of forcing it.
26    fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self>;
27}
28
29// Blanket impl of `DepNodeKey`, which is specialized by other impls elsewhere.
30impl<'tcx, T> DepNodeKey<'tcx> for T
31where
32    T: StableHash + Debug,
33{
34    #[inline(always)]
35    default fn key_fingerprint_style() -> KeyFingerprintStyle {
36        KeyFingerprintStyle::Opaque
37    }
38
39    #[inline(always)]
40    default fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
41        tcx.with_stable_hashing_context(|mut hcx| {
42            let mut hasher = StableHasher::new();
43            self.stable_hash(&mut hcx, &mut hasher);
44            hasher.finish()
45        })
46    }
47
48    #[inline(always)]
49    default fn try_recover_key(_: TyCtxt<'tcx>, _: &DepNode) -> Option<Self> {
50        None
51    }
52}
53
54impl<'tcx> DepNodeKey<'tcx> for () {
55    #[inline(always)]
56    fn key_fingerprint_style() -> KeyFingerprintStyle {
57        KeyFingerprintStyle::Unit
58    }
59
60    #[inline(always)]
61    fn to_fingerprint(&self, _: TyCtxt<'tcx>) -> Fingerprint {
62        Fingerprint::ZERO
63    }
64
65    #[inline(always)]
66    fn try_recover_key(_: TyCtxt<'tcx>, _: &DepNode) -> Option<Self> {
67        Some(())
68    }
69}
70
71impl<'tcx> DepNodeKey<'tcx> for DefId {
72    #[inline(always)]
73    fn key_fingerprint_style() -> KeyFingerprintStyle {
74        KeyFingerprintStyle::DefPathHash
75    }
76
77    #[inline(always)]
78    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
79        tcx.def_path_hash(*self).0
80    }
81
82    #[inline(always)]
83    fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
84        dep_node.extract_def_id(tcx)
85    }
86}
87
88impl<'tcx> DepNodeKey<'tcx> for LocalDefId {
89    #[inline(always)]
90    fn key_fingerprint_style() -> KeyFingerprintStyle {
91        KeyFingerprintStyle::DefPathHash
92    }
93
94    #[inline(always)]
95    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
96        self.to_def_id().to_fingerprint(tcx)
97    }
98
99    #[inline(always)]
100    fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
101        dep_node.extract_def_id(tcx).map(|id| id.expect_local())
102    }
103}
104
105impl<'tcx> DepNodeKey<'tcx> for OwnerId {
106    #[inline(always)]
107    fn key_fingerprint_style() -> KeyFingerprintStyle {
108        KeyFingerprintStyle::DefPathHash
109    }
110
111    #[inline(always)]
112    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
113        self.to_def_id().to_fingerprint(tcx)
114    }
115
116    #[inline(always)]
117    fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
118        dep_node.extract_def_id(tcx).map(|id| OwnerId { def_id: id.expect_local() })
119    }
120}
121
122impl<'tcx> DepNodeKey<'tcx> for CrateNum {
123    #[inline(always)]
124    fn key_fingerprint_style() -> KeyFingerprintStyle {
125        KeyFingerprintStyle::DefPathHash
126    }
127
128    #[inline(always)]
129    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
130        let def_id = self.as_def_id();
131        def_id.to_fingerprint(tcx)
132    }
133
134    #[inline(always)]
135    fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
136        dep_node.extract_def_id(tcx).map(|id| id.krate)
137    }
138}
139
140impl<'tcx> DepNodeKey<'tcx> for (DefId, DefId) {
141    #[inline(always)]
142    fn key_fingerprint_style() -> KeyFingerprintStyle {
143        KeyFingerprintStyle::Opaque
144    }
145
146    // We actually would not need to specialize the implementation of this
147    // method but it's faster to combine the hashes than to instantiate a full
148    // hashing context and stable-hashing state.
149    #[inline(always)]
150    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
151        let (def_id_0, def_id_1) = *self;
152
153        let def_path_hash_0 = tcx.def_path_hash(def_id_0);
154        let def_path_hash_1 = tcx.def_path_hash(def_id_1);
155
156        def_path_hash_0.0.combine(def_path_hash_1.0)
157    }
158}
159
160impl<'tcx> DepNodeKey<'tcx> for HirId {
161    #[inline(always)]
162    fn key_fingerprint_style() -> KeyFingerprintStyle {
163        KeyFingerprintStyle::HirId
164    }
165
166    // We actually would not need to specialize the implementation of this
167    // method but it's faster to combine the hashes than to instantiate a full
168    // hashing context and stable-hashing state.
169    #[inline(always)]
170    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
171        let HirId { owner, local_id } = *self;
172        let def_path_hash = tcx.def_path_hash(owner.to_def_id());
173        Fingerprint::new(
174            // `owner` is local, so is completely defined by the local hash
175            def_path_hash.local_hash(),
176            local_id.as_u32() as u64,
177        )
178    }
179
180    #[inline(always)]
181    fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
182        if tcx.key_fingerprint_style(dep_node.kind) == KeyFingerprintStyle::HirId {
183            let (local_hash, local_id) = Fingerprint::from(dep_node.key_fingerprint).split();
184            let def_path_hash = DefPathHash::new(tcx.stable_crate_id(LOCAL_CRATE), local_hash);
185            let def_id = tcx.def_path_hash_to_def_id(def_path_hash)?.expect_local();
186            let local_id = local_id
187                .as_u64()
188                .try_into()
189                .unwrap_or_else(|_| {
    ::core::panicking::panic_fmt(format_args!("local id should be u32, found {0:?}",
            local_id));
}panic!("local id should be u32, found {local_id:?}"));
190            Some(HirId { owner: OwnerId { def_id }, local_id: ItemLocalId::from_u32(local_id) })
191        } else {
192            None
193        }
194    }
195}
196
197impl<'tcx> DepNodeKey<'tcx> for ModDefId {
198    #[inline(always)]
199    fn key_fingerprint_style() -> KeyFingerprintStyle {
200        KeyFingerprintStyle::DefPathHash
201    }
202
203    #[inline(always)]
204    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
205        self.to_def_id().to_fingerprint(tcx)
206    }
207
208    #[inline(always)]
209    fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
210        DefId::try_recover_key(tcx, dep_node).map(ModDefId::new_unchecked)
211    }
212}
213
214impl<'tcx> DepNodeKey<'tcx> for LocalModDefId {
215    #[inline(always)]
216    fn key_fingerprint_style() -> KeyFingerprintStyle {
217        KeyFingerprintStyle::DefPathHash
218    }
219
220    #[inline(always)]
221    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
222        self.to_def_id().to_fingerprint(tcx)
223    }
224
225    #[inline(always)]
226    fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
227        LocalDefId::try_recover_key(tcx, dep_node).map(LocalModDefId::new_unchecked)
228    }
229}