]> git.lizzy.rs Git - rust.git/blob - src/librustc_middle/ich/hcx.rs
Rollup merge of #73418 - doctorn:variants-intrinsic, r=kennytm
[rust.git] / src / librustc_middle / ich / hcx.rs
1 use crate::ich;
2 use crate::middle::cstore::CrateStore;
3 use crate::ty::{fast_reject, TyCtxt};
4
5 use rustc_ast::ast;
6 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
7 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
8 use rustc_data_structures::sync::Lrc;
9 use rustc_hir as hir;
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};
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     fn new_with_or_without_spans(
71         sess: &'a Session,
72         krate: &'a hir::Crate<'a>,
73         definitions: &'a Definitions,
74         cstore: &'a dyn CrateStore,
75         always_ignore_spans: bool,
76     ) -> Self {
77         let hash_spans_initial =
78             !always_ignore_spans && !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 new(
95         sess: &'a Session,
96         krate: &'a hir::Crate<'a>,
97         definitions: &'a Definitions,
98         cstore: &'a dyn CrateStore,
99     ) -> Self {
100         Self::new_with_or_without_spans(
101             sess,
102             krate,
103             definitions,
104             cstore,
105             /*always_ignore_spans=*/ false,
106         )
107     }
108
109     #[inline]
110     pub fn ignore_spans(
111         sess: &'a Session,
112         krate: &'a hir::Crate<'a>,
113         definitions: &'a Definitions,
114         cstore: &'a dyn CrateStore,
115     ) -> Self {
116         let always_ignore_spans = true;
117         Self::new_with_or_without_spans(sess, krate, definitions, cstore, always_ignore_spans)
118     }
119
120     #[inline]
121     pub fn sess(&self) -> &'a Session {
122         self.sess
123     }
124
125     #[inline]
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;
129         f(self);
130         self.hash_bodies = prev_hash_bodies;
131     }
132
133     #[inline]
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;
137         f(self);
138         self.hash_spans = prev_hash_spans;
139     }
140
141     #[inline]
142     pub fn with_node_id_hashing_mode<F: FnOnce(&mut Self)>(
143         &mut self,
144         mode: NodeIdHashingMode,
145         f: F,
146     ) {
147         let prev = self.node_id_hashing_mode;
148         self.node_id_hashing_mode = mode;
149         f(self);
150         self.node_id_hashing_mode = prev;
151     }
152
153     #[inline]
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)
157         } else {
158             self.cstore.def_path_hash(def_id)
159         }
160     }
161
162     #[inline]
163     pub fn local_def_path_hash(&self, def_id: LocalDefId) -> DefPathHash {
164         self.definitions.def_path_hash(def_id)
165     }
166
167     #[inline]
168     pub fn hash_bodies(&self) -> bool {
169         self.hash_bodies
170     }
171
172     #[inline]
173     pub fn source_map(&mut self) -> &mut CachingSourceMapView<'a> {
174         match self.caching_source_map {
175             Some(ref mut sm) => sm,
176             ref mut none => {
177                 *none = Some(CachingSourceMapView::new(self.raw_source_map));
178                 none.as_mut().unwrap()
179             }
180         }
181     }
182
183     #[inline]
184     pub fn is_ignored_attr(&self, name: Symbol) -> bool {
185         thread_local! {
186             static IGNORED_ATTRIBUTES: FxHashSet<Symbol> = compute_ignored_attr_names();
187         }
188         IGNORED_ATTRIBUTES.with(|attrs| attrs.contains(&name))
189     }
190 }
191
192 /// Something that can provide a stable hashing context.
193 pub trait StableHashingContextProvider<'a> {
194     fn get_stable_hashing_context(&self) -> StableHashingContext<'a>;
195 }
196
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()
200     }
201 }
202
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()
206     }
207 }
208
209 impl StableHashingContextProvider<'tcx> for TyCtxt<'tcx> {
210     fn get_stable_hashing_context(&self) -> StableHashingContext<'tcx> {
211         (*self).create_stable_hashing_context()
212     }
213 }
214
215 impl<'a> StableHashingContextProvider<'a> for StableHashingContext<'a> {
216     fn get_stable_hashing_context(&self) -> StableHashingContext<'a> {
217         self.clone()
218     }
219 }
220
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");
224     }
225 }
226
227 impl<'a> rustc_span::HashStableContext for StableHashingContext<'a> {
228     fn hash_spans(&self) -> bool {
229         self.hash_spans
230     }
231
232     #[inline]
233     fn hash_def_id(&mut self, def_id: DefId, hasher: &mut StableHasher) {
234         let hcx = self;
235         hcx.def_path_hash(def_id).hash_stable(hcx, hasher);
236     }
237
238     fn byte_pos_to_line_and_col(
239         &mut self,
240         byte: BytePos,
241     ) -> Option<(Lrc<SourceFile>, usize, BytePos)> {
242         self.source_map().byte_pos_to_line_and_col(byte)
243     }
244 }
245
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>>,
251 ) {
252     {
253         let mut blanket_impls: SmallVec<[_; 8]> =
254             blanket_impls.iter().map(|&def_id| hcx.def_path_hash(def_id)).collect();
255
256         if blanket_impls.len() > 1 {
257             blanket_impls.sort_unstable();
258         }
259
260         blanket_impls.hash_stable(hcx, hasher);
261     }
262
263     {
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();
272
273             if impls.len() > 1 {
274                 impls.sort_unstable();
275             }
276
277             impls.hash_stable(hcx, hasher);
278         }
279     }
280 }