]> git.lizzy.rs Git - rust.git/blob - src/librustc/ich/hcx.rs
Rollup merge of #67837 - GuillaumeGomez:clean-up-err-codes, r=Dylan-DPC
[rust.git] / src / librustc / ich / hcx.rs
1 use crate::hir;
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};
9
10 use std::cmp::Ord;
11
12 use rustc_span::source_map::SourceMap;
13 use rustc_span::symbol::Symbol;
14 use rustc_span::{BytePos, SourceFile};
15 use syntax::ast;
16
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;
21
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()
25 }
26
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).
31 #[derive(Clone)]
32 pub struct StableHashingContext<'a> {
33     sess: &'a Session,
34     definitions: &'a Definitions,
35     cstore: &'a dyn CrateStore,
36     body_resolver: BodyResolver<'a>,
37     hash_spans: bool,
38     hash_bodies: bool,
39     node_id_hashing_mode: NodeIdHashingMode,
40
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>>,
45 }
46
47 #[derive(PartialEq, Eq, Clone, Copy)]
48 pub enum NodeIdHashingMode {
49     Ignore,
50     HashDefPath,
51 }
52
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>);
58
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> {
63         self.0.body(id)
64     }
65 }
66
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.
71     #[inline]
72     pub fn new(
73         sess: &'a Session,
74         krate: &'a hir::Crate<'a>,
75         definitions: &'a Definitions,
76         cstore: &'a dyn CrateStore,
77     ) -> Self {
78         let hash_spans_initial = !sess.opts.debugging_opts.incremental_ignore_spans;
79
80         StableHashingContext {
81             sess,
82             body_resolver: BodyResolver(krate),
83             definitions,
84             cstore,
85             caching_source_map: None,
86             raw_source_map: sess.source_map(),
87             hash_spans: hash_spans_initial,
88             hash_bodies: true,
89             node_id_hashing_mode: NodeIdHashingMode::HashDefPath,
90         }
91     }
92
93     #[inline]
94     pub fn sess(&self) -> &'a Session {
95         self.sess
96     }
97
98     #[inline]
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;
102         f(self);
103         self.hash_bodies = prev_hash_bodies;
104     }
105
106     #[inline]
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;
110         f(self);
111         self.hash_spans = prev_hash_spans;
112     }
113
114     #[inline]
115     pub fn with_node_id_hashing_mode<F: FnOnce(&mut Self)>(
116         &mut self,
117         mode: NodeIdHashingMode,
118         f: F,
119     ) {
120         let prev = self.node_id_hashing_mode;
121         self.node_id_hashing_mode = mode;
122         f(self);
123         self.node_id_hashing_mode = prev;
124     }
125
126     #[inline]
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)
130         } else {
131             self.cstore.def_path_hash(def_id)
132         }
133     }
134
135     #[inline]
136     pub fn local_def_path_hash(&self, def_index: DefIndex) -> DefPathHash {
137         self.definitions.def_path_hash(def_index)
138     }
139
140     #[inline]
141     pub fn node_to_hir_id(&self, node_id: ast::NodeId) -> hir::HirId {
142         self.definitions.node_to_hir_id(node_id)
143     }
144
145     #[inline]
146     pub fn hash_bodies(&self) -> bool {
147         self.hash_bodies
148     }
149
150     #[inline]
151     pub fn source_map(&mut self) -> &mut CachingSourceMapView<'a> {
152         match self.caching_source_map {
153             Some(ref mut cm) => cm,
154             ref mut none => {
155                 *none = Some(CachingSourceMapView::new(self.raw_source_map));
156                 none.as_mut().unwrap()
157             }
158         }
159     }
160
161     #[inline]
162     pub fn is_ignored_attr(&self, name: Symbol) -> bool {
163         thread_local! {
164             static IGNORED_ATTRIBUTES: FxHashSet<Symbol> = compute_ignored_attr_names();
165         }
166         IGNORED_ATTRIBUTES.with(|attrs| attrs.contains(&name))
167     }
168
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;
172
173         f(self);
174
175         self.node_id_hashing_mode = prev_hash_node_ids;
176     }
177 }
178
179 /// Something that can provide a stable hashing context.
180 pub trait StableHashingContextProvider<'a> {
181     fn get_stable_hashing_context(&self) -> StableHashingContext<'a>;
182 }
183
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()
187     }
188 }
189
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()
193     }
194 }
195
196 impl StableHashingContextProvider<'tcx> for TyCtxt<'tcx> {
197     fn get_stable_hashing_context(&self) -> StableHashingContext<'tcx> {
198         (*self).create_stable_hashing_context()
199     }
200 }
201
202 impl<'a> StableHashingContextProvider<'a> for StableHashingContext<'a> {
203     fn get_stable_hashing_context(&self) -> StableHashingContext<'a> {
204         self.clone()
205     }
206 }
207
208 impl<'a> crate::dep_graph::DepGraphSafe for StableHashingContext<'a> {}
209
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);
214         }
215     }
216 }
217
218 impl<'a> HashStable<StableHashingContext<'a>> for hir::HirId {
219     #[inline]
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.
224             }
225             NodeIdHashingMode::HashDefPath => {
226                 let hir::HirId { owner, local_id } = *self;
227
228                 hcx.local_def_path_hash(owner).hash_stable(hcx, hasher);
229                 local_id.hash_stable(hcx, hasher);
230             }
231         }
232     }
233 }
234
235 impl<'a> ToStableHashKey<StableHashingContext<'a>> for hir::HirId {
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         let def_path_hash = hcx.local_def_path_hash(self.owner);
244         (def_path_hash, self.local_id)
245     }
246 }
247
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.
253             }
254             NodeIdHashingMode::HashDefPath => {
255                 hcx.definitions.node_to_hir_id(*self).hash_stable(hcx, hasher);
256             }
257         }
258     }
259 }
260
261 impl<'a> ToStableHashKey<StableHashingContext<'a>> for ast::NodeId {
262     type KeyType = (DefPathHash, hir::ItemLocalId);
263
264     #[inline]
265     fn to_stable_hash_key(
266         &self,
267         hcx: &StableHashingContext<'a>,
268     ) -> (DefPathHash, hir::ItemLocalId) {
269         hcx.definitions.node_to_hir_id(*self).to_stable_hash_key(hcx)
270     }
271 }
272
273 impl<'a> rustc_span::HashStableContext for StableHashingContext<'a> {
274     fn hash_spans(&self) -> bool {
275         self.hash_spans
276     }
277
278     fn byte_pos_to_line_and_col(
279         &mut self,
280         byte: BytePos,
281     ) -> Option<(Lrc<SourceFile>, usize, BytePos)> {
282         self.source_map().byte_pos_to_line_and_col(byte)
283     }
284 }
285
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>>,
291 ) {
292     {
293         let mut blanket_impls: SmallVec<[_; 8]> =
294             blanket_impls.iter().map(|&def_id| hcx.def_path_hash(def_id)).collect();
295
296         if blanket_impls.len() > 1 {
297             blanket_impls.sort_unstable();
298         }
299
300         blanket_impls.hash_stable(hcx, hasher);
301     }
302
303     {
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();
312
313             if impls.len() > 1 {
314                 impls.sort_unstable();
315             }
316
317             impls.hash_stable(hcx, hasher);
318         }
319     }
320 }