]> git.lizzy.rs Git - rust.git/blob - src/librustc/ich/hcx.rs
Rollup merge of #70038 - DutchGhost:const-forget-tests, r=RalfJung
[rust.git] / src / librustc / ich / hcx.rs
1 use crate::hir::map::definitions::{DefPathHash, Definitions};
2 use crate::ich::{self, CachingSourceMapView};
3 use crate::middle::cstore::CrateStore;
4 use crate::ty::{fast_reject, TyCtxt};
5
6 use rustc_ast::ast;
7 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
8 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
9 use rustc_data_structures::sync::Lrc;
10 use rustc_hir as hir;
11 use rustc_hir::def_id::{DefId, LocalDefId};
12 use rustc_session::Session;
13 use rustc_span::source_map::SourceMap;
14 use rustc_span::symbol::Symbol;
15 use rustc_span::{BytePos, SourceFile};
16
17 use smallvec::SmallVec;
18 use std::cmp::Ord;
19
20 fn compute_ignored_attr_names() -> FxHashSet<Symbol> {
21     debug_assert!(!ich::IGNORED_ATTRIBUTES.is_empty());
22     ich::IGNORED_ATTRIBUTES.iter().copied().collect()
23 }
24
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).
29 #[derive(Clone)]
30 pub struct StableHashingContext<'a> {
31     sess: &'a Session,
32     definitions: &'a Definitions,
33     cstore: &'a dyn CrateStore,
34     pub(super) body_resolver: BodyResolver<'a>,
35     hash_spans: bool,
36     hash_bodies: bool,
37     pub(super) node_id_hashing_mode: NodeIdHashingMode,
38
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>>,
43 }
44
45 #[derive(PartialEq, Eq, Clone, Copy)]
46 pub enum NodeIdHashingMode {
47     Ignore,
48     HashDefPath,
49 }
50
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>);
56
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> {
61         self.0.body(id)
62     }
63 }
64
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.
69     #[inline]
70     pub fn new(
71         sess: &'a Session,
72         krate: &'a hir::Crate<'a>,
73         definitions: &'a Definitions,
74         cstore: &'a dyn CrateStore,
75     ) -> Self {
76         let hash_spans_initial = !sess.opts.debugging_opts.incremental_ignore_spans;
77
78         StableHashingContext {
79             sess,
80             body_resolver: BodyResolver(krate),
81             definitions,
82             cstore,
83             caching_source_map: None,
84             raw_source_map: sess.source_map(),
85             hash_spans: hash_spans_initial,
86             hash_bodies: true,
87             node_id_hashing_mode: NodeIdHashingMode::HashDefPath,
88         }
89     }
90
91     #[inline]
92     pub fn sess(&self) -> &'a Session {
93         self.sess
94     }
95
96     #[inline]
97     pub fn while_hashing_hir_bodies<F: FnOnce(&mut Self)>(&mut self, hash_bodies: bool, f: F) {
98         let prev_hash_bodies = self.hash_bodies;
99         self.hash_bodies = hash_bodies;
100         f(self);
101         self.hash_bodies = prev_hash_bodies;
102     }
103
104     #[inline]
105     pub fn while_hashing_spans<F: FnOnce(&mut Self)>(&mut self, hash_spans: bool, f: F) {
106         let prev_hash_spans = self.hash_spans;
107         self.hash_spans = hash_spans;
108         f(self);
109         self.hash_spans = prev_hash_spans;
110     }
111
112     #[inline]
113     pub fn with_node_id_hashing_mode<F: FnOnce(&mut Self)>(
114         &mut self,
115         mode: NodeIdHashingMode,
116         f: F,
117     ) {
118         let prev = self.node_id_hashing_mode;
119         self.node_id_hashing_mode = mode;
120         f(self);
121         self.node_id_hashing_mode = prev;
122     }
123
124     #[inline]
125     pub fn def_path_hash(&self, def_id: DefId) -> DefPathHash {
126         if let Some(def_id) = def_id.as_local() {
127             self.local_def_path_hash(def_id)
128         } else {
129             self.cstore.def_path_hash(def_id)
130         }
131     }
132
133     #[inline]
134     pub fn local_def_path_hash(&self, def_id: LocalDefId) -> DefPathHash {
135         self.definitions.def_path_hash(def_id)
136     }
137
138     #[inline]
139     pub fn node_to_hir_id(&self, node_id: ast::NodeId) -> hir::HirId {
140         self.definitions.node_to_hir_id(node_id)
141     }
142
143     #[inline]
144     pub fn hash_bodies(&self) -> bool {
145         self.hash_bodies
146     }
147
148     #[inline]
149     pub fn source_map(&mut self) -> &mut CachingSourceMapView<'a> {
150         match self.caching_source_map {
151             Some(ref mut sm) => sm,
152             ref mut none => {
153                 *none = Some(CachingSourceMapView::new(self.raw_source_map));
154                 none.as_mut().unwrap()
155             }
156         }
157     }
158
159     #[inline]
160     pub fn is_ignored_attr(&self, name: Symbol) -> bool {
161         thread_local! {
162             static IGNORED_ATTRIBUTES: FxHashSet<Symbol> = compute_ignored_attr_names();
163         }
164         IGNORED_ATTRIBUTES.with(|attrs| attrs.contains(&name))
165     }
166 }
167
168 /// Something that can provide a stable hashing context.
169 pub trait StableHashingContextProvider<'a> {
170     fn get_stable_hashing_context(&self) -> StableHashingContext<'a>;
171 }
172
173 impl<'a, 'b, T: StableHashingContextProvider<'a>> StableHashingContextProvider<'a> for &'b T {
174     fn get_stable_hashing_context(&self) -> StableHashingContext<'a> {
175         (**self).get_stable_hashing_context()
176     }
177 }
178
179 impl<'a, 'b, T: StableHashingContextProvider<'a>> StableHashingContextProvider<'a> for &'b mut T {
180     fn get_stable_hashing_context(&self) -> StableHashingContext<'a> {
181         (**self).get_stable_hashing_context()
182     }
183 }
184
185 impl StableHashingContextProvider<'tcx> for TyCtxt<'tcx> {
186     fn get_stable_hashing_context(&self) -> StableHashingContext<'tcx> {
187         (*self).create_stable_hashing_context()
188     }
189 }
190
191 impl<'a> StableHashingContextProvider<'a> for StableHashingContext<'a> {
192     fn get_stable_hashing_context(&self) -> StableHashingContext<'a> {
193         self.clone()
194     }
195 }
196
197 impl<'a> crate::dep_graph::DepGraphSafe for StableHashingContext<'a> {}
198
199 impl<'a> HashStable<StableHashingContext<'a>> for ast::NodeId {
200     fn hash_stable(&self, _: &mut StableHashingContext<'a>, _: &mut StableHasher) {
201         panic!("Node IDs should not appear in incremental state");
202     }
203 }
204
205 impl<'a> rustc_span::HashStableContext for StableHashingContext<'a> {
206     fn hash_spans(&self) -> bool {
207         self.hash_spans
208     }
209
210     #[inline]
211     fn hash_def_id(&mut self, def_id: DefId, hasher: &mut StableHasher) {
212         let hcx = self;
213         hcx.def_path_hash(def_id).hash_stable(hcx, hasher);
214     }
215
216     fn byte_pos_to_line_and_col(
217         &mut self,
218         byte: BytePos,
219     ) -> Option<(Lrc<SourceFile>, usize, BytePos)> {
220         self.source_map().byte_pos_to_line_and_col(byte)
221     }
222 }
223
224 pub fn hash_stable_trait_impls<'a>(
225     hcx: &mut StableHashingContext<'a>,
226     hasher: &mut StableHasher,
227     blanket_impls: &[DefId],
228     non_blanket_impls: &FxHashMap<fast_reject::SimplifiedType, Vec<DefId>>,
229 ) {
230     {
231         let mut blanket_impls: SmallVec<[_; 8]> =
232             blanket_impls.iter().map(|&def_id| hcx.def_path_hash(def_id)).collect();
233
234         if blanket_impls.len() > 1 {
235             blanket_impls.sort_unstable();
236         }
237
238         blanket_impls.hash_stable(hcx, hasher);
239     }
240
241     {
242         let mut keys: SmallVec<[_; 8]> =
243             non_blanket_impls.keys().map(|k| (k, k.map_def(|d| hcx.def_path_hash(d)))).collect();
244         keys.sort_unstable_by(|&(_, ref k1), &(_, ref k2)| k1.cmp(k2));
245         keys.len().hash_stable(hcx, hasher);
246         for (key, ref stable_key) in keys {
247             stable_key.hash_stable(hcx, hasher);
248             let mut impls: SmallVec<[_; 8]> =
249                 non_blanket_impls[key].iter().map(|&impl_id| hcx.def_path_hash(impl_id)).collect();
250
251             if impls.len() > 1 {
252                 impls.sort_unstable();
253             }
254
255             impls.hash_stable(hcx, hasher);
256         }
257     }
258 }