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::{HashStable, 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::ich::StableHashingContext;
11use crate::ty::TyCtxt;
12
13/// Trait for query keys as seen by dependency-node tracking.
14pub trait DepNodeKey<'tcx>: Debug + Sized {
15    fn key_fingerprint_style() -> KeyFingerprintStyle;
16
17    /// This method turns a query key into an opaque `Fingerprint` to be used
18    /// in `DepNode`.
19    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint;
20
21    fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String;
22
23    /// This method tries to recover the query key from the given `DepNode`,
24    /// something which is needed when forcing `DepNode`s during red-green
25    /// evaluation. The query system will only call this method if
26    /// `fingerprint_style()` is not `FingerprintStyle::Opaque`.
27    /// It is always valid to return `None` here, in which case incremental
28    /// compilation will treat the query as having changed instead of forcing it.
29    fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self>;
30}
31
32// Blanket impl of `DepNodeKey`, which is specialized by other impls elsewhere.
33impl<'tcx, T> DepNodeKey<'tcx> for T
34where
35    T: for<'a> HashStable<StableHashingContext<'a>> + Debug,
36{
37    #[inline(always)]
38    default fn key_fingerprint_style() -> KeyFingerprintStyle {
39        KeyFingerprintStyle::Opaque
40    }
41
42    #[inline(always)]
43    default fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
44        tcx.with_stable_hashing_context(|mut hcx| {
45            let mut hasher = StableHasher::new();
46            self.hash_stable(&mut hcx, &mut hasher);
47            hasher.finish()
48        })
49    }
50
51    #[inline(always)]
52    default fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
53        // Make sure to print dep node params with reduced queries since printing
54        // may themselves call queries, which may lead to (possibly untracked!)
55        // query cycles.
56        tcx.with_reduced_queries(|| ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0:?}", self))
    })format!("{self:?}"))
57    }
58
59    #[inline(always)]
60    default fn try_recover_key(_: TyCtxt<'tcx>, _: &DepNode) -> Option<Self> {
61        None
62    }
63}
64
65impl<'tcx> DepNodeKey<'tcx> for () {
66    #[inline(always)]
67    fn key_fingerprint_style() -> KeyFingerprintStyle {
68        KeyFingerprintStyle::Unit
69    }
70
71    #[inline(always)]
72    fn to_fingerprint(&self, _: TyCtxt<'tcx>) -> Fingerprint {
73        Fingerprint::ZERO
74    }
75
76    #[inline(always)]
77    fn try_recover_key(_: TyCtxt<'tcx>, _: &DepNode) -> Option<Self> {
78        Some(())
79    }
80}
81
82impl<'tcx> DepNodeKey<'tcx> for DefId {
83    #[inline(always)]
84    fn key_fingerprint_style() -> KeyFingerprintStyle {
85        KeyFingerprintStyle::DefPathHash
86    }
87
88    #[inline(always)]
89    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
90        tcx.def_path_hash(*self).0
91    }
92
93    #[inline(always)]
94    fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
95        tcx.def_path_str(*self)
96    }
97
98    #[inline(always)]
99    fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
100        dep_node.extract_def_id(tcx)
101    }
102}
103
104impl<'tcx> DepNodeKey<'tcx> for LocalDefId {
105    #[inline(always)]
106    fn key_fingerprint_style() -> KeyFingerprintStyle {
107        KeyFingerprintStyle::DefPathHash
108    }
109
110    #[inline(always)]
111    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
112        self.to_def_id().to_fingerprint(tcx)
113    }
114
115    #[inline(always)]
116    fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
117        self.to_def_id().to_debug_str(tcx)
118    }
119
120    #[inline(always)]
121    fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
122        dep_node.extract_def_id(tcx).map(|id| id.expect_local())
123    }
124}
125
126impl<'tcx> DepNodeKey<'tcx> for OwnerId {
127    #[inline(always)]
128    fn key_fingerprint_style() -> KeyFingerprintStyle {
129        KeyFingerprintStyle::DefPathHash
130    }
131
132    #[inline(always)]
133    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
134        self.to_def_id().to_fingerprint(tcx)
135    }
136
137    #[inline(always)]
138    fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
139        self.to_def_id().to_debug_str(tcx)
140    }
141
142    #[inline(always)]
143    fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
144        dep_node.extract_def_id(tcx).map(|id| OwnerId { def_id: id.expect_local() })
145    }
146}
147
148impl<'tcx> DepNodeKey<'tcx> for CrateNum {
149    #[inline(always)]
150    fn key_fingerprint_style() -> KeyFingerprintStyle {
151        KeyFingerprintStyle::DefPathHash
152    }
153
154    #[inline(always)]
155    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
156        let def_id = self.as_def_id();
157        def_id.to_fingerprint(tcx)
158    }
159
160    #[inline(always)]
161    fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
162        tcx.crate_name(*self).to_string()
163    }
164
165    #[inline(always)]
166    fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
167        dep_node.extract_def_id(tcx).map(|id| id.krate)
168    }
169}
170
171impl<'tcx> DepNodeKey<'tcx> for (DefId, DefId) {
172    #[inline(always)]
173    fn key_fingerprint_style() -> KeyFingerprintStyle {
174        KeyFingerprintStyle::Opaque
175    }
176
177    // We actually would not need to specialize the implementation of this
178    // method but it's faster to combine the hashes than to instantiate a full
179    // hashing context and stable-hashing state.
180    #[inline(always)]
181    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
182        let (def_id_0, def_id_1) = *self;
183
184        let def_path_hash_0 = tcx.def_path_hash(def_id_0);
185        let def_path_hash_1 = tcx.def_path_hash(def_id_1);
186
187        def_path_hash_0.0.combine(def_path_hash_1.0)
188    }
189
190    #[inline(always)]
191    fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
192        let (def_id_0, def_id_1) = *self;
193
194        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("({0}, {1})",
                tcx.def_path_debug_str(def_id_0),
                tcx.def_path_debug_str(def_id_1)))
    })format!("({}, {})", tcx.def_path_debug_str(def_id_0), tcx.def_path_debug_str(def_id_1))
195    }
196}
197
198impl<'tcx> DepNodeKey<'tcx> for HirId {
199    #[inline(always)]
200    fn key_fingerprint_style() -> KeyFingerprintStyle {
201        KeyFingerprintStyle::HirId
202    }
203
204    // We actually would not need to specialize the implementation of this
205    // method but it's faster to combine the hashes than to instantiate a full
206    // hashing context and stable-hashing state.
207    #[inline(always)]
208    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
209        let HirId { owner, local_id } = *self;
210        let def_path_hash = tcx.def_path_hash(owner.to_def_id());
211        Fingerprint::new(
212            // `owner` is local, so is completely defined by the local hash
213            def_path_hash.local_hash(),
214            local_id.as_u32() as u64,
215        )
216    }
217
218    #[inline(always)]
219    fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
220        let HirId { owner, local_id } = *self;
221        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}.{1}", tcx.def_path_str(owner),
                local_id.as_u32()))
    })format!("{}.{}", tcx.def_path_str(owner), local_id.as_u32())
222    }
223
224    #[inline(always)]
225    fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
226        if tcx.key_fingerprint_style(dep_node.kind) == KeyFingerprintStyle::HirId {
227            let (local_hash, local_id) = Fingerprint::from(dep_node.key_fingerprint).split();
228            let def_path_hash = DefPathHash::new(tcx.stable_crate_id(LOCAL_CRATE), local_hash);
229            let def_id = tcx.def_path_hash_to_def_id(def_path_hash)?.expect_local();
230            let local_id = local_id
231                .as_u64()
232                .try_into()
233                .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:?}"));
234            Some(HirId { owner: OwnerId { def_id }, local_id: ItemLocalId::from_u32(local_id) })
235        } else {
236            None
237        }
238    }
239}
240
241impl<'tcx> DepNodeKey<'tcx> for ModDefId {
242    #[inline(always)]
243    fn key_fingerprint_style() -> KeyFingerprintStyle {
244        KeyFingerprintStyle::DefPathHash
245    }
246
247    #[inline(always)]
248    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
249        self.to_def_id().to_fingerprint(tcx)
250    }
251
252    #[inline(always)]
253    fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
254        self.to_def_id().to_debug_str(tcx)
255    }
256
257    #[inline(always)]
258    fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
259        DefId::try_recover_key(tcx, dep_node).map(ModDefId::new_unchecked)
260    }
261}
262
263impl<'tcx> DepNodeKey<'tcx> for LocalModDefId {
264    #[inline(always)]
265    fn key_fingerprint_style() -> KeyFingerprintStyle {
266        KeyFingerprintStyle::DefPathHash
267    }
268
269    #[inline(always)]
270    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
271        self.to_def_id().to_fingerprint(tcx)
272    }
273
274    #[inline(always)]
275    fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
276        self.to_def_id().to_debug_str(tcx)
277    }
278
279    #[inline(always)]
280    fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
281        LocalDefId::try_recover_key(tcx, dep_node).map(LocalModDefId::new_unchecked)
282    }
283}