2 use crate::middle::cstore::CrateStore;
3 use crate::ty::{fast_reject, TyCtxt};
6 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
7 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
8 use rustc_data_structures::sync::Lrc;
10 use rustc_hir::def_id::{DefId, LocalDefId};
11 use rustc_hir::definitions::{DefPathHash, Definitions};
12 use rustc_session::Session;
13 use rustc_span::source_map::SourceMap;
14 use rustc_span::symbol::Symbol;
15 use rustc_span::{BytePos, CachingSourceMapView, SourceFile};
17 use smallvec::SmallVec;
20 fn compute_ignored_attr_names() -> FxHashSet<Symbol> {
21 debug_assert!(!ich::IGNORED_ATTRIBUTES.is_empty());
22 ich::IGNORED_ATTRIBUTES.iter().copied().collect()
25 /// This is the context state available during incr. comp. hashing. It contains
26 /// enough information to transform `DefId`s and `HirId`s into stable `DefPath`s (i.e.,
27 /// a reference to the `TyCtxt`) and it holds a few caches for speeding up various
28 /// things (e.g., each `DefId`/`DefPath` is only hashed once).
30 pub struct StableHashingContext<'a> {
32 definitions: &'a Definitions,
33 cstore: &'a dyn CrateStore,
34 pub(super) body_resolver: BodyResolver<'a>,
37 pub(super) node_id_hashing_mode: NodeIdHashingMode,
39 // Very often, we are hashing something that does not need the
40 // `CachingSourceMapView`, so we initialize it lazily.
41 raw_source_map: &'a SourceMap,
42 caching_source_map: Option<CachingSourceMapView<'a>>,
45 #[derive(PartialEq, Eq, Clone, Copy)]
46 pub enum NodeIdHashingMode {
51 /// The `BodyResolver` allows mapping a `BodyId` to the corresponding `hir::Body`.
52 /// We could also just store a plain reference to the `hir::Crate` but we want
53 /// to avoid that the crate is used to get untracked access to all of the HIR.
54 #[derive(Clone, Copy)]
55 pub(super) struct BodyResolver<'tcx>(&'tcx hir::Crate<'tcx>);
57 impl<'tcx> BodyResolver<'tcx> {
58 /// Returns a reference to the `hir::Body` with the given `BodyId`.
59 /// **Does not do any tracking**; use carefully.
60 pub(super) fn body(self, id: hir::BodyId) -> &'tcx hir::Body<'tcx> {
65 impl<'a> StableHashingContext<'a> {
66 /// The `krate` here is only used for mapping `BodyId`s to `Body`s.
67 /// Don't use it for anything else or you'll run the risk of
68 /// leaking data out of the tracking system.
70 fn new_with_or_without_spans(
72 krate: &'a hir::Crate<'a>,
73 definitions: &'a Definitions,
74 cstore: &'a dyn CrateStore,
75 always_ignore_spans: bool,
77 let hash_spans_initial =
78 !always_ignore_spans && !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,
96 krate: &'a hir::Crate<'a>,
97 definitions: &'a Definitions,
98 cstore: &'a dyn CrateStore,
100 Self::new_with_or_without_spans(
105 /*always_ignore_spans=*/ false,
112 krate: &'a hir::Crate<'a>,
113 definitions: &'a Definitions,
114 cstore: &'a dyn CrateStore,
116 let always_ignore_spans = true;
117 Self::new_with_or_without_spans(sess, krate, definitions, cstore, always_ignore_spans)
121 pub fn sess(&self) -> &'a Session {
126 pub fn while_hashing_hir_bodies<F: FnOnce(&mut Self)>(&mut self, hash_bodies: bool, f: F) {
127 let prev_hash_bodies = self.hash_bodies;
128 self.hash_bodies = hash_bodies;
130 self.hash_bodies = prev_hash_bodies;
134 pub fn while_hashing_spans<F: FnOnce(&mut Self)>(&mut self, hash_spans: bool, f: F) {
135 let prev_hash_spans = self.hash_spans;
136 self.hash_spans = hash_spans;
138 self.hash_spans = prev_hash_spans;
142 pub fn with_node_id_hashing_mode<F: FnOnce(&mut Self)>(
144 mode: NodeIdHashingMode,
147 let prev = self.node_id_hashing_mode;
148 self.node_id_hashing_mode = mode;
150 self.node_id_hashing_mode = prev;
154 pub fn def_path_hash(&self, def_id: DefId) -> DefPathHash {
155 if let Some(def_id) = def_id.as_local() {
156 self.local_def_path_hash(def_id)
158 self.cstore.def_path_hash(def_id)
163 pub fn local_def_path_hash(&self, def_id: LocalDefId) -> DefPathHash {
164 self.definitions.def_path_hash(def_id)
168 pub fn hash_bodies(&self) -> bool {
173 pub fn source_map(&mut self) -> &mut CachingSourceMapView<'a> {
174 match self.caching_source_map {
175 Some(ref mut sm) => sm,
177 *none = Some(CachingSourceMapView::new(self.raw_source_map));
178 none.as_mut().unwrap()
184 pub fn is_ignored_attr(&self, name: Symbol) -> bool {
186 static IGNORED_ATTRIBUTES: FxHashSet<Symbol> = compute_ignored_attr_names();
188 IGNORED_ATTRIBUTES.with(|attrs| attrs.contains(&name))
192 /// Something that can provide a stable hashing context.
193 pub trait StableHashingContextProvider<'a> {
194 fn get_stable_hashing_context(&self) -> StableHashingContext<'a>;
197 impl<'a, 'b, T: StableHashingContextProvider<'a>> StableHashingContextProvider<'a> for &'b T {
198 fn get_stable_hashing_context(&self) -> StableHashingContext<'a> {
199 (**self).get_stable_hashing_context()
203 impl<'a, 'b, T: StableHashingContextProvider<'a>> StableHashingContextProvider<'a> for &'b mut T {
204 fn get_stable_hashing_context(&self) -> StableHashingContext<'a> {
205 (**self).get_stable_hashing_context()
209 impl StableHashingContextProvider<'tcx> for TyCtxt<'tcx> {
210 fn get_stable_hashing_context(&self) -> StableHashingContext<'tcx> {
211 (*self).create_stable_hashing_context()
215 impl<'a> StableHashingContextProvider<'a> for StableHashingContext<'a> {
216 fn get_stable_hashing_context(&self) -> StableHashingContext<'a> {
221 impl<'a> HashStable<StableHashingContext<'a>> for ast::NodeId {
222 fn hash_stable(&self, _: &mut StableHashingContext<'a>, _: &mut StableHasher) {
223 panic!("Node IDs should not appear in incremental state");
227 impl<'a> rustc_span::HashStableContext for StableHashingContext<'a> {
228 fn hash_spans(&self) -> bool {
233 fn hash_def_id(&mut self, def_id: DefId, hasher: &mut StableHasher) {
235 hcx.def_path_hash(def_id).hash_stable(hcx, hasher);
238 fn byte_pos_to_line_and_col(
241 ) -> Option<(Lrc<SourceFile>, usize, BytePos)> {
242 self.source_map().byte_pos_to_line_and_col(byte)
246 pub fn hash_stable_trait_impls<'a>(
247 hcx: &mut StableHashingContext<'a>,
248 hasher: &mut StableHasher,
249 blanket_impls: &[DefId],
250 non_blanket_impls: &FxHashMap<fast_reject::SimplifiedType, Vec<DefId>>,
253 let mut blanket_impls: SmallVec<[_; 8]> =
254 blanket_impls.iter().map(|&def_id| hcx.def_path_hash(def_id)).collect();
256 if blanket_impls.len() > 1 {
257 blanket_impls.sort_unstable();
260 blanket_impls.hash_stable(hcx, hasher);
264 let mut keys: SmallVec<[_; 8]> =
265 non_blanket_impls.keys().map(|k| (k, k.map_def(|d| hcx.def_path_hash(d)))).collect();
266 keys.sort_unstable_by(|&(_, ref k1), &(_, ref k2)| k1.cmp(k2));
267 keys.len().hash_stable(hcx, hasher);
268 for (key, ref stable_key) in keys {
269 stable_key.hash_stable(hcx, hasher);
270 let mut impls: SmallVec<[_; 8]> =
271 non_blanket_impls[key].iter().map(|&impl_id| hcx.def_path_hash(impl_id)).collect();
274 impls.sort_unstable();
277 impls.hash_stable(hcx, hasher);