2 use crate::hir::def_id::{DefId, DefIndex};
3 use crate::hir::map::definitions::Definitions;
4 use crate::hir::map::DefPathHash;
5 use crate::ich::{self, CachingSourceMapView};
6 use crate::middle::cstore::CrateStore;
7 use crate::session::Session;
8 use crate::ty::{fast_reject, TyCtxt};
12 use rustc_span::source_map::SourceMap;
13 use rustc_span::symbol::Symbol;
14 use rustc_span::{BytePos, SourceFile};
17 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
18 use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
19 use rustc_data_structures::sync::Lrc;
20 use smallvec::SmallVec;
22 fn compute_ignored_attr_names() -> FxHashSet<Symbol> {
23 debug_assert!(ich::IGNORED_ATTRIBUTES.len() > 0);
24 ich::IGNORED_ATTRIBUTES.iter().map(|&s| s).collect()
27 /// This is the context state available during incr. comp. hashing. It contains
28 /// enough information to transform `DefId`s and `HirId`s into stable `DefPath`s (i.e.,
29 /// a reference to the `TyCtxt`) and it holds a few caches for speeding up various
30 /// things (e.g., each `DefId`/`DefPath` is only hashed once).
32 pub struct StableHashingContext<'a> {
34 definitions: &'a Definitions,
35 cstore: &'a dyn CrateStore,
36 body_resolver: BodyResolver<'a>,
39 node_id_hashing_mode: NodeIdHashingMode,
41 // Very often, we are hashing something that does not need the
42 // `CachingSourceMapView`, so we initialize it lazily.
43 raw_source_map: &'a SourceMap,
44 caching_source_map: Option<CachingSourceMapView<'a>>,
47 #[derive(PartialEq, Eq, Clone, Copy)]
48 pub enum NodeIdHashingMode {
53 /// The `BodyResolver` allows mapping a `BodyId` to the corresponding `hir::Body`.
54 /// We could also just store a plain reference to the `hir::Crate` but we want
55 /// to avoid that the crate is used to get untracked access to all of the HIR.
56 #[derive(Clone, Copy)]
57 struct BodyResolver<'tcx>(&'tcx hir::Crate<'tcx>);
59 impl<'tcx> BodyResolver<'tcx> {
60 /// Returns a reference to the `hir::Body` with the given `BodyId`.
61 /// **Does not do any tracking**; use carefully.
62 fn body(self, id: hir::BodyId) -> &'tcx hir::Body<'tcx> {
67 impl<'a> StableHashingContext<'a> {
68 /// The `krate` here is only used for mapping `BodyId`s to `Body`s.
69 /// Don't use it for anything else or you'll run the risk of
70 /// leaking data out of the tracking system.
74 krate: &'a hir::Crate<'a>,
75 definitions: &'a Definitions,
76 cstore: &'a dyn CrateStore,
78 let hash_spans_initial = !sess.opts.debugging_opts.incremental_ignore_spans;
80 StableHashingContext {
82 body_resolver: BodyResolver(krate),
85 caching_source_map: None,
86 raw_source_map: sess.source_map(),
87 hash_spans: hash_spans_initial,
89 node_id_hashing_mode: NodeIdHashingMode::HashDefPath,
94 pub fn sess(&self) -> &'a Session {
99 pub fn while_hashing_hir_bodies<F: FnOnce(&mut Self)>(&mut self, hash_bodies: bool, f: F) {
100 let prev_hash_bodies = self.hash_bodies;
101 self.hash_bodies = hash_bodies;
103 self.hash_bodies = prev_hash_bodies;
107 pub fn while_hashing_spans<F: FnOnce(&mut Self)>(&mut self, hash_spans: bool, f: F) {
108 let prev_hash_spans = self.hash_spans;
109 self.hash_spans = hash_spans;
111 self.hash_spans = prev_hash_spans;
115 pub fn with_node_id_hashing_mode<F: FnOnce(&mut Self)>(
117 mode: NodeIdHashingMode,
120 let prev = self.node_id_hashing_mode;
121 self.node_id_hashing_mode = mode;
123 self.node_id_hashing_mode = prev;
127 pub fn def_path_hash(&self, def_id: DefId) -> DefPathHash {
128 if def_id.is_local() {
129 self.definitions.def_path_hash(def_id.index)
131 self.cstore.def_path_hash(def_id)
136 pub fn local_def_path_hash(&self, def_index: DefIndex) -> DefPathHash {
137 self.definitions.def_path_hash(def_index)
141 pub fn node_to_hir_id(&self, node_id: ast::NodeId) -> hir::HirId {
142 self.definitions.node_to_hir_id(node_id)
146 pub fn hash_bodies(&self) -> bool {
151 pub fn source_map(&mut self) -> &mut CachingSourceMapView<'a> {
152 match self.caching_source_map {
153 Some(ref mut cm) => cm,
155 *none = Some(CachingSourceMapView::new(self.raw_source_map));
156 none.as_mut().unwrap()
162 pub fn is_ignored_attr(&self, name: Symbol) -> bool {
164 static IGNORED_ATTRIBUTES: FxHashSet<Symbol> = compute_ignored_attr_names();
166 IGNORED_ATTRIBUTES.with(|attrs| attrs.contains(&name))
169 pub fn hash_hir_item_like<F: FnOnce(&mut Self)>(&mut self, f: F) {
170 let prev_hash_node_ids = self.node_id_hashing_mode;
171 self.node_id_hashing_mode = NodeIdHashingMode::Ignore;
175 self.node_id_hashing_mode = prev_hash_node_ids;
179 /// Something that can provide a stable hashing context.
180 pub trait StableHashingContextProvider<'a> {
181 fn get_stable_hashing_context(&self) -> StableHashingContext<'a>;
184 impl<'a, 'b, T: StableHashingContextProvider<'a>> StableHashingContextProvider<'a> for &'b T {
185 fn get_stable_hashing_context(&self) -> StableHashingContext<'a> {
186 (**self).get_stable_hashing_context()
190 impl<'a, 'b, T: StableHashingContextProvider<'a>> StableHashingContextProvider<'a> for &'b mut T {
191 fn get_stable_hashing_context(&self) -> StableHashingContext<'a> {
192 (**self).get_stable_hashing_context()
196 impl StableHashingContextProvider<'tcx> for TyCtxt<'tcx> {
197 fn get_stable_hashing_context(&self) -> StableHashingContext<'tcx> {
198 (*self).create_stable_hashing_context()
202 impl<'a> StableHashingContextProvider<'a> for StableHashingContext<'a> {
203 fn get_stable_hashing_context(&self) -> StableHashingContext<'a> {
208 impl<'a> crate::dep_graph::DepGraphSafe for StableHashingContext<'a> {}
210 impl<'a> HashStable<StableHashingContext<'a>> for hir::BodyId {
211 fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
212 if hcx.hash_bodies() {
213 hcx.body_resolver.body(*self).hash_stable(hcx, hasher);
218 impl<'a> HashStable<StableHashingContext<'a>> for hir::HirId {
220 fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
221 match hcx.node_id_hashing_mode {
222 NodeIdHashingMode::Ignore => {
223 // Don't do anything.
225 NodeIdHashingMode::HashDefPath => {
226 let hir::HirId { owner, local_id } = *self;
228 hcx.local_def_path_hash(owner).hash_stable(hcx, hasher);
229 local_id.hash_stable(hcx, hasher);
235 impl<'a> ToStableHashKey<StableHashingContext<'a>> for hir::HirId {
236 type KeyType = (DefPathHash, hir::ItemLocalId);
239 fn to_stable_hash_key(
241 hcx: &StableHashingContext<'a>,
242 ) -> (DefPathHash, hir::ItemLocalId) {
243 let def_path_hash = hcx.local_def_path_hash(self.owner);
244 (def_path_hash, self.local_id)
248 impl<'a> HashStable<StableHashingContext<'a>> for ast::NodeId {
249 fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
250 match hcx.node_id_hashing_mode {
251 NodeIdHashingMode::Ignore => {
252 // Don't do anything.
254 NodeIdHashingMode::HashDefPath => {
255 hcx.definitions.node_to_hir_id(*self).hash_stable(hcx, hasher);
261 impl<'a> ToStableHashKey<StableHashingContext<'a>> for ast::NodeId {
262 type KeyType = (DefPathHash, hir::ItemLocalId);
265 fn to_stable_hash_key(
267 hcx: &StableHashingContext<'a>,
268 ) -> (DefPathHash, hir::ItemLocalId) {
269 hcx.definitions.node_to_hir_id(*self).to_stable_hash_key(hcx)
273 impl<'a> rustc_span::HashStableContext for StableHashingContext<'a> {
274 fn hash_spans(&self) -> bool {
278 fn byte_pos_to_line_and_col(
281 ) -> Option<(Lrc<SourceFile>, usize, BytePos)> {
282 self.source_map().byte_pos_to_line_and_col(byte)
286 pub fn hash_stable_trait_impls<'a>(
287 hcx: &mut StableHashingContext<'a>,
288 hasher: &mut StableHasher,
289 blanket_impls: &[DefId],
290 non_blanket_impls: &FxHashMap<fast_reject::SimplifiedType, Vec<DefId>>,
293 let mut blanket_impls: SmallVec<[_; 8]> =
294 blanket_impls.iter().map(|&def_id| hcx.def_path_hash(def_id)).collect();
296 if blanket_impls.len() > 1 {
297 blanket_impls.sort_unstable();
300 blanket_impls.hash_stable(hcx, hasher);
304 let mut keys: SmallVec<[_; 8]> =
305 non_blanket_impls.keys().map(|k| (k, k.map_def(|d| hcx.def_path_hash(d)))).collect();
306 keys.sort_unstable_by(|&(_, ref k1), &(_, ref k2)| k1.cmp(k2));
307 keys.len().hash_stable(hcx, hasher);
308 for (key, ref stable_key) in keys {
309 stable_key.hash_stable(hcx, hasher);
310 let mut impls: SmallVec<[_; 8]> =
311 non_blanket_impls[key].iter().map(|&impl_id| hcx.def_path_hash(impl_id)).collect();
314 impls.sort_unstable();
317 impls.hash_stable(hcx, hasher);