2 use crate::hir::def_id::{DefId, DefIndex};
3 use crate::hir::map::DefPathHash;
4 use crate::hir::map::definitions::Definitions;
5 use crate::ich::{self, CachingSourceMapView, Fingerprint};
6 use crate::middle::cstore::CrateStore;
7 use crate::ty::{TyCtxt, fast_reject};
8 use crate::session::Session;
11 use std::hash as std_hash;
12 use std::cell::RefCell;
16 use syntax::source_map::SourceMap;
17 use syntax::ext::hygiene::SyntaxContext;
18 use syntax::symbol::Symbol;
19 use syntax::tokenstream::DelimSpan;
20 use syntax_pos::{Span, DUMMY_SP};
21 use syntax_pos::hygiene;
23 use rustc_data_structures::stable_hasher::{HashStable,
24 StableHasher, StableHasherResult,
26 use rustc_data_structures::fx::{FxHashSet, FxHashMap};
27 use smallvec::SmallVec;
29 fn compute_ignored_attr_names() -> FxHashSet<Symbol> {
30 debug_assert!(ich::IGNORED_ATTRIBUTES.len() > 0);
31 ich::IGNORED_ATTRIBUTES.iter().map(|&s| s).collect()
34 /// This is the context state available during incr. comp. hashing. It contains
35 /// enough information to transform DefIds and HirIds into stable DefPaths (i.e.
36 /// a reference to the TyCtxt) and it holds a few caches for speeding up various
37 /// things (e.g., each DefId/DefPath is only hashed once).
39 pub struct StableHashingContext<'a> {
41 definitions: &'a Definitions,
42 cstore: &'a dyn CrateStore,
43 body_resolver: BodyResolver<'a>,
46 node_id_hashing_mode: NodeIdHashingMode,
48 // Very often, we are hashing something that does not need the
49 // CachingSourceMapView, so we initialize it lazily.
50 raw_source_map: &'a SourceMap,
51 caching_source_map: Option<CachingSourceMapView<'a>>,
54 #[derive(PartialEq, Eq, Clone, Copy)]
55 pub enum NodeIdHashingMode {
60 /// The BodyResolver allows to map a BodyId to the corresponding hir::Body.
61 /// We could also just store a plain reference to the hir::Crate but we want
62 /// to avoid that the crate is used to get untracked access to all of the HIR.
63 #[derive(Clone, Copy)]
64 struct BodyResolver<'tcx>(&'tcx hir::Crate);
66 impl<'tcx> BodyResolver<'tcx> {
67 // Return a reference to the hir::Body with the given BodyId.
68 // DOES NOT DO ANY TRACKING, use carefully.
69 fn body(self, id: hir::BodyId) -> &'tcx hir::Body {
74 impl<'a> StableHashingContext<'a> {
75 // The `krate` here is only used for mapping BodyIds to Bodies.
76 // Don't use it for anything else or you'll run the risk of
77 // leaking data out of the tracking system.
79 pub fn new(sess: &'a Session,
80 krate: &'a hir::Crate,
81 definitions: &'a Definitions,
82 cstore: &'a dyn CrateStore)
84 let hash_spans_initial = !sess.opts.debugging_opts.incremental_ignore_spans;
86 StableHashingContext {
88 body_resolver: BodyResolver(krate),
91 caching_source_map: None,
92 raw_source_map: sess.source_map(),
93 hash_spans: hash_spans_initial,
95 node_id_hashing_mode: NodeIdHashingMode::HashDefPath,
100 pub fn sess(&self) -> &'a Session {
105 pub fn while_hashing_hir_bodies<F: FnOnce(&mut Self)>(&mut self,
108 let prev_hash_bodies = self.hash_bodies;
109 self.hash_bodies = hash_bodies;
111 self.hash_bodies = prev_hash_bodies;
115 pub fn while_hashing_spans<F: FnOnce(&mut Self)>(&mut self,
118 let prev_hash_spans = self.hash_spans;
119 self.hash_spans = hash_spans;
121 self.hash_spans = prev_hash_spans;
125 pub fn with_node_id_hashing_mode<F: FnOnce(&mut Self)>(&mut self,
126 mode: NodeIdHashingMode,
128 let prev = self.node_id_hashing_mode;
129 self.node_id_hashing_mode = mode;
131 self.node_id_hashing_mode = prev;
135 pub fn def_path_hash(&self, def_id: DefId) -> DefPathHash {
136 if def_id.is_local() {
137 self.definitions.def_path_hash(def_id.index)
139 self.cstore.def_path_hash(def_id)
144 pub fn local_def_path_hash(&self, def_index: DefIndex) -> DefPathHash {
145 self.definitions.def_path_hash(def_index)
149 pub fn node_to_hir_id(&self, node_id: ast::NodeId) -> hir::HirId {
150 self.definitions.node_to_hir_id(node_id)
154 pub fn hash_bodies(&self) -> bool {
159 pub fn source_map(&mut self) -> &mut CachingSourceMapView<'a> {
160 match self.caching_source_map {
161 Some(ref mut cm) => {
165 *none = Some(CachingSourceMapView::new(self.raw_source_map));
166 none.as_mut().unwrap()
172 pub fn is_ignored_attr(&self, name: Symbol) -> bool {
174 static IGNORED_ATTRIBUTES: FxHashSet<Symbol> = compute_ignored_attr_names();
176 IGNORED_ATTRIBUTES.with(|attrs| attrs.contains(&name))
179 pub fn hash_hir_item_like<F: FnOnce(&mut Self)>(&mut self, f: F) {
180 let prev_hash_node_ids = self.node_id_hashing_mode;
181 self.node_id_hashing_mode = NodeIdHashingMode::Ignore;
185 self.node_id_hashing_mode = prev_hash_node_ids;
189 /// Something that can provide a stable hashing context.
190 pub trait StableHashingContextProvider<'a> {
191 fn get_stable_hashing_context(&self) -> StableHashingContext<'a>;
194 impl<'a, 'b, T: StableHashingContextProvider<'a>> StableHashingContextProvider<'a>
196 fn get_stable_hashing_context(&self) -> StableHashingContext<'a> {
197 (**self).get_stable_hashing_context()
201 impl<'a, 'b, T: StableHashingContextProvider<'a>> StableHashingContextProvider<'a>
203 fn get_stable_hashing_context(&self) -> StableHashingContext<'a> {
204 (**self).get_stable_hashing_context()
208 impl StableHashingContextProvider<'tcx> for TyCtxt<'tcx> {
209 fn get_stable_hashing_context(&self) -> StableHashingContext<'tcx> {
210 (*self).create_stable_hashing_context()
214 impl<'a> StableHashingContextProvider<'a> for StableHashingContext<'a> {
215 fn get_stable_hashing_context(&self) -> StableHashingContext<'a> {
220 impl<'a> crate::dep_graph::DepGraphSafe for StableHashingContext<'a> {
224 impl<'a> HashStable<StableHashingContext<'a>> for hir::BodyId {
225 fn hash_stable<W: StableHasherResult>(&self,
226 hcx: &mut StableHashingContext<'a>,
227 hasher: &mut StableHasher<W>) {
228 if hcx.hash_bodies() {
229 hcx.body_resolver.body(*self).hash_stable(hcx, hasher);
234 impl<'a> HashStable<StableHashingContext<'a>> for hir::HirId {
236 fn hash_stable<W: StableHasherResult>(&self,
237 hcx: &mut StableHashingContext<'a>,
238 hasher: &mut StableHasher<W>) {
239 match hcx.node_id_hashing_mode {
240 NodeIdHashingMode::Ignore => {
241 // Don't do anything.
243 NodeIdHashingMode::HashDefPath => {
249 hcx.local_def_path_hash(owner).hash_stable(hcx, hasher);
250 local_id.hash_stable(hcx, hasher);
256 impl<'a> ToStableHashKey<StableHashingContext<'a>> for hir::HirId {
257 type KeyType = (DefPathHash, hir::ItemLocalId);
260 fn to_stable_hash_key(&self,
261 hcx: &StableHashingContext<'a>)
262 -> (DefPathHash, hir::ItemLocalId) {
263 let def_path_hash = hcx.local_def_path_hash(self.owner);
264 (def_path_hash, self.local_id)
268 impl<'a> HashStable<StableHashingContext<'a>> for ast::NodeId {
269 fn hash_stable<W: StableHasherResult>(&self,
270 hcx: &mut StableHashingContext<'a>,
271 hasher: &mut StableHasher<W>) {
272 match hcx.node_id_hashing_mode {
273 NodeIdHashingMode::Ignore => {
274 // Don't do anything.
276 NodeIdHashingMode::HashDefPath => {
277 hcx.definitions.node_to_hir_id(*self).hash_stable(hcx, hasher);
283 impl<'a> ToStableHashKey<StableHashingContext<'a>> for ast::NodeId {
284 type KeyType = (DefPathHash, hir::ItemLocalId);
287 fn to_stable_hash_key(&self,
288 hcx: &StableHashingContext<'a>)
289 -> (DefPathHash, hir::ItemLocalId) {
290 hcx.definitions.node_to_hir_id(*self).to_stable_hash_key(hcx)
294 impl<'a> HashStable<StableHashingContext<'a>> for Span {
296 // Hash a span in a stable way. We can't directly hash the span's BytePos
297 // fields (that would be similar to hashing pointers, since those are just
298 // offsets into the SourceMap). Instead, we hash the (file name, line, column)
299 // triple, which stays the same even if the containing SourceFile has moved
300 // within the SourceMap.
301 // Also note that we are hashing byte offsets for the column, not unicode
302 // codepoint offsets. For the purpose of the hash that's sufficient.
303 // Also, hashing filenames is expensive so we avoid doing it twice when the
304 // span starts and ends in the same file, which is almost always the case.
305 fn hash_stable<W: StableHasherResult>(&self,
306 hcx: &mut StableHashingContext<'a>,
307 hasher: &mut StableHasher<W>) {
308 const TAG_VALID_SPAN: u8 = 0;
309 const TAG_INVALID_SPAN: u8 = 1;
310 const TAG_EXPANSION: u8 = 0;
311 const TAG_NO_EXPANSION: u8 = 1;
317 if *self == DUMMY_SP {
318 return std_hash::Hash::hash(&TAG_INVALID_SPAN, hasher);
321 // If this is not an empty or invalid span, we want to hash the last
322 // position that belongs to it, as opposed to hashing the first
324 let span = self.data();
326 if span.hi < span.lo {
327 return std_hash::Hash::hash(&TAG_INVALID_SPAN, hasher);
330 let (file_lo, line_lo, col_lo) = match hcx.source_map()
331 .byte_pos_to_line_and_col(span.lo) {
334 return std_hash::Hash::hash(&TAG_INVALID_SPAN, hasher);
338 if !file_lo.contains(span.hi) {
339 return std_hash::Hash::hash(&TAG_INVALID_SPAN, hasher);
342 std_hash::Hash::hash(&TAG_VALID_SPAN, hasher);
343 // We truncate the stable_id hash and line and col numbers. The chances
344 // of causing a collision this way should be minimal.
345 std_hash::Hash::hash(&(file_lo.name_hash as u64), hasher);
347 let col = (col_lo.0 as u64) & 0xFF;
348 let line = ((line_lo as u64) & 0xFF_FF_FF) << 8;
349 let len = ((span.hi - span.lo).0 as u64) << 32;
350 let line_col_len = col | line | len;
351 std_hash::Hash::hash(&line_col_len, hasher);
353 if span.ctxt == SyntaxContext::root() {
354 TAG_NO_EXPANSION.hash_stable(hcx, hasher);
356 TAG_EXPANSION.hash_stable(hcx, hasher);
358 // Since the same expansion context is usually referenced many
359 // times, we cache a stable hash of it and hash that instead of
360 // recursing every time.
362 static CACHE: RefCell<FxHashMap<hygiene::ExpnId, u64>> = Default::default();
365 let sub_hash: u64 = CACHE.with(|cache| {
366 let expn_id = span.ctxt.outer_expn();
368 if let Some(&sub_hash) = cache.borrow().get(&expn_id) {
372 let mut hasher = StableHasher::new();
373 expn_id.expn_info().hash_stable(hcx, &mut hasher);
374 let sub_hash: Fingerprint = hasher.finish();
375 let sub_hash = sub_hash.to_smaller_hash();
376 cache.borrow_mut().insert(expn_id, sub_hash);
380 sub_hash.hash_stable(hcx, hasher);
385 impl<'a> HashStable<StableHashingContext<'a>> for DelimSpan {
386 fn hash_stable<W: StableHasherResult>(
388 hcx: &mut StableHashingContext<'a>,
389 hasher: &mut StableHasher<W>,
391 self.open.hash_stable(hcx, hasher);
392 self.close.hash_stable(hcx, hasher);
396 pub fn hash_stable_trait_impls<'a, W>(
397 hcx: &mut StableHashingContext<'a>,
398 hasher: &mut StableHasher<W>,
399 blanket_impls: &[DefId],
400 non_blanket_impls: &FxHashMap<fast_reject::SimplifiedType, Vec<DefId>>,
402 W: StableHasherResult,
405 let mut blanket_impls: SmallVec<[_; 8]> = blanket_impls
407 .map(|&def_id| hcx.def_path_hash(def_id))
410 if blanket_impls.len() > 1 {
411 blanket_impls.sort_unstable();
414 blanket_impls.hash_stable(hcx, hasher);
418 let mut keys: SmallVec<[_; 8]> =
419 non_blanket_impls.keys()
420 .map(|k| (k, k.map_def(|d| hcx.def_path_hash(d))))
422 keys.sort_unstable_by(|&(_, ref k1), &(_, ref k2)| k1.cmp(k2));
423 keys.len().hash_stable(hcx, hasher);
424 for (key, ref stable_key) in keys {
425 stable_key.hash_stable(hcx, hasher);
426 let mut impls : SmallVec<[_; 8]> = non_blanket_impls[key]
428 .map(|&impl_id| hcx.def_path_hash(impl_id))
432 impls.sort_unstable();
435 impls.hash_stable(hcx, hasher);