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