]> git.lizzy.rs Git - rust.git/blob - src/librustc/ich/hcx.rs
Move librustc_hir/def_id.rs to librustc_span/def_id.rs
[rust.git] / src / librustc / ich / hcx.rs
1 use crate::hir::map::definitions::Definitions;
2 use crate::hir::map::DefPathHash;
3 use crate::ich::{self, CachingSourceMapView};
4 use crate::middle::cstore::CrateStore;
5 use crate::session::Session;
6 use crate::ty::{fast_reject, TyCtxt};
7
8 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
9 use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
10 use rustc_data_structures::sync::Lrc;
11 use rustc_hir as hir;
12 use rustc_hir::def_id::{DefId, DefIndex};
13 use rustc_span::source_map::SourceMap;
14 use rustc_span::symbol::Symbol;
15 use rustc_span::{BytePos, SourceFile};
16 use syntax::ast;
17
18 use smallvec::SmallVec;
19 use std::cmp::Ord;
20
21 fn compute_ignored_attr_names() -> FxHashSet<Symbol> {
22     debug_assert!(ich::IGNORED_ATTRIBUTES.len() > 0);
23     ich::IGNORED_ATTRIBUTES.iter().map(|&s| s).collect()
24 }
25
26 /// This is the context state available during incr. comp. hashing. It contains
27 /// enough information to transform `DefId`s and `HirId`s into stable `DefPath`s (i.e.,
28 /// a reference to the `TyCtxt`) and it holds a few caches for speeding up various
29 /// things (e.g., each `DefId`/`DefPath` is only hashed once).
30 #[derive(Clone)]
31 pub struct StableHashingContext<'a> {
32     sess: &'a Session,
33     definitions: &'a Definitions,
34     cstore: &'a dyn CrateStore,
35     pub(super) body_resolver: BodyResolver<'a>,
36     hash_spans: bool,
37     hash_bodies: bool,
38     pub(super) node_id_hashing_mode: NodeIdHashingMode,
39
40     // Very often, we are hashing something that does not need the
41     // `CachingSourceMapView`, so we initialize it lazily.
42     raw_source_map: &'a SourceMap,
43     caching_source_map: Option<CachingSourceMapView<'a>>,
44 }
45
46 #[derive(PartialEq, Eq, Clone, Copy)]
47 pub enum NodeIdHashingMode {
48     Ignore,
49     HashDefPath,
50 }
51
52 /// The `BodyResolver` allows mapping a `BodyId` to the corresponding `hir::Body`.
53 /// We could also just store a plain reference to the `hir::Crate` but we want
54 /// to avoid that the crate is used to get untracked access to all of the HIR.
55 #[derive(Clone, Copy)]
56 pub(super) struct BodyResolver<'tcx>(&'tcx hir::Crate<'tcx>);
57
58 impl<'tcx> BodyResolver<'tcx> {
59     /// Returns a reference to the `hir::Body` with the given `BodyId`.
60     /// **Does not do any tracking**; use carefully.
61     pub(super) fn body(self, id: hir::BodyId) -> &'tcx hir::Body<'tcx> {
62         self.0.body(id)
63     }
64 }
65
66 impl<'a> StableHashingContext<'a> {
67     /// The `krate` here is only used for mapping `BodyId`s to `Body`s.
68     /// Don't use it for anything else or you'll run the risk of
69     /// leaking data out of the tracking system.
70     #[inline]
71     pub fn new(
72         sess: &'a Session,
73         krate: &'a hir::Crate<'a>,
74         definitions: &'a Definitions,
75         cstore: &'a dyn CrateStore,
76     ) -> Self {
77         let hash_spans_initial = !sess.opts.debugging_opts.incremental_ignore_spans;
78
79         StableHashingContext {
80             sess,
81             body_resolver: BodyResolver(krate),
82             definitions,
83             cstore,
84             caching_source_map: None,
85             raw_source_map: sess.source_map(),
86             hash_spans: hash_spans_initial,
87             hash_bodies: true,
88             node_id_hashing_mode: NodeIdHashingMode::HashDefPath,
89         }
90     }
91
92     #[inline]
93     pub fn sess(&self) -> &'a Session {
94         self.sess
95     }
96
97     #[inline]
98     pub fn while_hashing_hir_bodies<F: FnOnce(&mut Self)>(&mut self, hash_bodies: bool, f: F) {
99         let prev_hash_bodies = self.hash_bodies;
100         self.hash_bodies = hash_bodies;
101         f(self);
102         self.hash_bodies = prev_hash_bodies;
103     }
104
105     #[inline]
106     pub fn while_hashing_spans<F: FnOnce(&mut Self)>(&mut self, hash_spans: bool, f: F) {
107         let prev_hash_spans = self.hash_spans;
108         self.hash_spans = hash_spans;
109         f(self);
110         self.hash_spans = prev_hash_spans;
111     }
112
113     #[inline]
114     pub fn with_node_id_hashing_mode<F: FnOnce(&mut Self)>(
115         &mut self,
116         mode: NodeIdHashingMode,
117         f: F,
118     ) {
119         let prev = self.node_id_hashing_mode;
120         self.node_id_hashing_mode = mode;
121         f(self);
122         self.node_id_hashing_mode = prev;
123     }
124
125     #[inline]
126     pub fn def_path_hash(&self, def_id: DefId) -> DefPathHash {
127         if def_id.is_local() {
128             self.definitions.def_path_hash(def_id.index)
129         } else {
130             self.cstore.def_path_hash(def_id)
131         }
132     }
133
134     #[inline]
135     pub fn local_def_path_hash(&self, def_index: DefIndex) -> DefPathHash {
136         self.definitions.def_path_hash(def_index)
137     }
138
139     #[inline]
140     pub fn node_to_hir_id(&self, node_id: ast::NodeId) -> hir::HirId {
141         self.definitions.node_to_hir_id(node_id)
142     }
143
144     #[inline]
145     pub fn hash_bodies(&self) -> bool {
146         self.hash_bodies
147     }
148
149     #[inline]
150     pub fn source_map(&mut self) -> &mut CachingSourceMapView<'a> {
151         match self.caching_source_map {
152             Some(ref mut cm) => cm,
153             ref mut none => {
154                 *none = Some(CachingSourceMapView::new(self.raw_source_map));
155                 none.as_mut().unwrap()
156             }
157         }
158     }
159
160     #[inline]
161     pub fn is_ignored_attr(&self, name: Symbol) -> bool {
162         thread_local! {
163             static IGNORED_ATTRIBUTES: FxHashSet<Symbol> = compute_ignored_attr_names();
164         }
165         IGNORED_ATTRIBUTES.with(|attrs| attrs.contains(&name))
166     }
167
168     pub fn hash_hir_item_like<F: FnOnce(&mut Self)>(&mut self, f: F) {
169         let prev_hash_node_ids = self.node_id_hashing_mode;
170         self.node_id_hashing_mode = NodeIdHashingMode::Ignore;
171
172         f(self);
173
174         self.node_id_hashing_mode = prev_hash_node_ids;
175     }
176 }
177
178 /// Something that can provide a stable hashing context.
179 pub trait StableHashingContextProvider<'a> {
180     fn get_stable_hashing_context(&self) -> StableHashingContext<'a>;
181 }
182
183 impl<'a, 'b, T: StableHashingContextProvider<'a>> StableHashingContextProvider<'a> for &'b T {
184     fn get_stable_hashing_context(&self) -> StableHashingContext<'a> {
185         (**self).get_stable_hashing_context()
186     }
187 }
188
189 impl<'a, 'b, T: StableHashingContextProvider<'a>> StableHashingContextProvider<'a> for &'b mut T {
190     fn get_stable_hashing_context(&self) -> StableHashingContext<'a> {
191         (**self).get_stable_hashing_context()
192     }
193 }
194
195 impl StableHashingContextProvider<'tcx> for TyCtxt<'tcx> {
196     fn get_stable_hashing_context(&self) -> StableHashingContext<'tcx> {
197         (*self).create_stable_hashing_context()
198     }
199 }
200
201 impl<'a> StableHashingContextProvider<'a> for StableHashingContext<'a> {
202     fn get_stable_hashing_context(&self) -> StableHashingContext<'a> {
203         self.clone()
204     }
205 }
206
207 impl<'a> crate::dep_graph::DepGraphSafe for StableHashingContext<'a> {}
208
209 impl<'a> ToStableHashKey<StableHashingContext<'a>> for hir::HirId {
210     type KeyType = (DefPathHash, hir::ItemLocalId);
211
212     #[inline]
213     fn to_stable_hash_key(
214         &self,
215         hcx: &StableHashingContext<'a>,
216     ) -> (DefPathHash, hir::ItemLocalId) {
217         let def_path_hash = hcx.local_def_path_hash(self.owner);
218         (def_path_hash, self.local_id)
219     }
220 }
221
222 impl<'a> HashStable<StableHashingContext<'a>> for ast::NodeId {
223     fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
224         match hcx.node_id_hashing_mode {
225             NodeIdHashingMode::Ignore => {
226                 // Don't do anything.
227             }
228             NodeIdHashingMode::HashDefPath => {
229                 hcx.definitions.node_to_hir_id(*self).hash_stable(hcx, hasher);
230             }
231         }
232     }
233 }
234
235 impl<'a> ToStableHashKey<StableHashingContext<'a>> for ast::NodeId {
236     type KeyType = (DefPathHash, hir::ItemLocalId);
237
238     #[inline]
239     fn to_stable_hash_key(
240         &self,
241         hcx: &StableHashingContext<'a>,
242     ) -> (DefPathHash, hir::ItemLocalId) {
243         hcx.definitions.node_to_hir_id(*self).to_stable_hash_key(hcx)
244     }
245 }
246
247 impl<'a> rustc_span::HashStableContext for StableHashingContext<'a> {
248     fn hash_spans(&self) -> bool {
249         self.hash_spans
250     }
251
252     #[inline]
253     fn hash_def_id(&mut self, def_id: DefId, hasher: &mut StableHasher) {
254         let hcx = self;
255         hcx.def_path_hash(def_id).hash_stable(hcx, hasher);
256     }
257
258     fn byte_pos_to_line_and_col(
259         &mut self,
260         byte: BytePos,
261     ) -> Option<(Lrc<SourceFile>, usize, BytePos)> {
262         self.source_map().byte_pos_to_line_and_col(byte)
263     }
264 }
265
266 pub fn hash_stable_trait_impls<'a>(
267     hcx: &mut StableHashingContext<'a>,
268     hasher: &mut StableHasher,
269     blanket_impls: &[DefId],
270     non_blanket_impls: &FxHashMap<fast_reject::SimplifiedType, Vec<DefId>>,
271 ) {
272     {
273         let mut blanket_impls: SmallVec<[_; 8]> =
274             blanket_impls.iter().map(|&def_id| hcx.def_path_hash(def_id)).collect();
275
276         if blanket_impls.len() > 1 {
277             blanket_impls.sort_unstable();
278         }
279
280         blanket_impls.hash_stable(hcx, hasher);
281     }
282
283     {
284         let mut keys: SmallVec<[_; 8]> =
285             non_blanket_impls.keys().map(|k| (k, k.map_def(|d| hcx.def_path_hash(d)))).collect();
286         keys.sort_unstable_by(|&(_, ref k1), &(_, ref k2)| k1.cmp(k2));
287         keys.len().hash_stable(hcx, hasher);
288         for (key, ref stable_key) in keys {
289             stable_key.hash_stable(hcx, hasher);
290             let mut impls: SmallVec<[_; 8]> =
291                 non_blanket_impls[key].iter().map(|&impl_id| hcx.def_path_hash(impl_id)).collect();
292
293             if impls.len() > 1 {
294                 impls.sort_unstable();
295             }
296
297             impls.hash_stable(hcx, hasher);
298         }
299     }
300 }