]> git.proxmox.com Git - rustc.git/blame - src/librustc_middle/ich/hcx.rs
New upstream version 1.47.0+dfsg1
[rustc.git] / src / librustc_middle / ich / hcx.rs
CommitLineData
ba9703b0 1use crate::ich;
9fa01778 2use crate::middle::cstore::CrateStore;
dfeec247 3use crate::ty::{fast_reject, TyCtxt};
cc61c64b 4
3dfed10e 5use rustc_ast as ast;
dfeec247 6use rustc_data_structures::fx::{FxHashMap, FxHashSet};
ba9703b0 7use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
60c5eb7d 8use rustc_data_structures::sync::Lrc;
dfeec247 9use rustc_hir as hir;
ba9703b0
XL
10use rustc_hir::def_id::{DefId, LocalDefId};
11use rustc_hir::definitions::{DefPathHash, Definitions};
12use rustc_session::Session;
dfeec247
XL
13use rustc_span::source_map::SourceMap;
14use rustc_span::symbol::Symbol;
ba9703b0 15use rustc_span::{BytePos, CachingSourceMapView, SourceFile};
dfeec247 16
3dfed10e 17use rustc_span::def_id::{CrateNum, CRATE_DEF_INDEX};
b7449926 18use smallvec::SmallVec;
dfeec247 19use std::cmp::Ord;
ea8adc8c 20
b7449926 21fn compute_ignored_attr_names() -> FxHashSet<Symbol> {
74b04a01
XL
22 debug_assert!(!ich::IGNORED_ATTRIBUTES.is_empty());
23 ich::IGNORED_ATTRIBUTES.iter().copied().collect()
2c00a5a8 24}
cc61c64b
XL
25
26/// This is the context state available during incr. comp. hashing. It contains
e1599b0c
XL
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).
ea8adc8c 30#[derive(Clone)]
0531ce1d
XL
31pub struct StableHashingContext<'a> {
32 sess: &'a Session,
33 definitions: &'a Definitions,
34 cstore: &'a dyn CrateStore,
dfeec247 35 pub(super) body_resolver: BodyResolver<'a>,
cc61c64b
XL
36 hash_spans: bool,
37 hash_bodies: bool,
dfeec247 38 pub(super) node_id_hashing_mode: NodeIdHashingMode,
ea8adc8c
XL
39
40 // Very often, we are hashing something that does not need the
e1599b0c 41 // `CachingSourceMapView`, so we initialize it lazily.
b7449926
XL
42 raw_source_map: &'a SourceMap,
43 caching_source_map: Option<CachingSourceMapView<'a>>,
cc61c64b
XL
44}
45
46#[derive(PartialEq, Eq, Clone, Copy)]
47pub enum NodeIdHashingMode {
48 Ignore,
49 HashDefPath,
cc61c64b
XL
50}
51
e1599b0c
XL
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
ea8adc8c
XL
54/// to avoid that the crate is used to get untracked access to all of the HIR.
55#[derive(Clone, Copy)]
dfeec247 56pub(super) struct BodyResolver<'tcx>(&'tcx hir::Crate<'tcx>);
ea8adc8c 57
dc9dc135 58impl<'tcx> BodyResolver<'tcx> {
e1599b0c
XL
59 /// Returns a reference to the `hir::Body` with the given `BodyId`.
60 /// **Does not do any tracking**; use carefully.
dfeec247 61 pub(super) fn body(self, id: hir::BodyId) -> &'tcx hir::Body<'tcx> {
ea8adc8c
XL
62 self.0.body(id)
63 }
64}
cc61c64b 65
0531ce1d 66impl<'a> StableHashingContext<'a> {
e1599b0c
XL
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.
0731742a 70 #[inline]
f035d41b 71 fn new_with_or_without_spans(
dfeec247
XL
72 sess: &'a Session,
73 krate: &'a hir::Crate<'a>,
74 definitions: &'a Definitions,
75 cstore: &'a dyn CrateStore,
f035d41b 76 always_ignore_spans: bool,
dfeec247 77 ) -> Self {
f035d41b
XL
78 let hash_spans_initial =
79 !always_ignore_spans && !sess.opts.debugging_opts.incremental_ignore_spans;
ea8adc8c 80
cc61c64b 81 StableHashingContext {
ea8adc8c
XL
82 sess,
83 body_resolver: BodyResolver(krate),
84 definitions,
85 cstore,
b7449926
XL
86 caching_source_map: None,
87 raw_source_map: sess.source_map(),
cc61c64b
XL
88 hash_spans: hash_spans_initial,
89 hash_bodies: true,
cc61c64b 90 node_id_hashing_mode: NodeIdHashingMode::HashDefPath,
cc61c64b
XL
91 }
92 }
93
f035d41b
XL
94 #[inline]
95 pub fn new(
96 sess: &'a Session,
97 krate: &'a hir::Crate<'a>,
98 definitions: &'a Definitions,
99 cstore: &'a dyn CrateStore,
100 ) -> Self {
101 Self::new_with_or_without_spans(
102 sess,
103 krate,
104 definitions,
105 cstore,
106 /*always_ignore_spans=*/ false,
107 )
108 }
109
110 #[inline]
111 pub fn ignore_spans(
112 sess: &'a Session,
113 krate: &'a hir::Crate<'a>,
114 definitions: &'a Definitions,
115 cstore: &'a dyn CrateStore,
116 ) -> Self {
117 let always_ignore_spans = true;
118 Self::new_with_or_without_spans(sess, krate, definitions, cstore, always_ignore_spans)
119 }
120
ea8adc8c 121 #[inline]
0531ce1d 122 pub fn sess(&self) -> &'a Session {
ea8adc8c
XL
123 self.sess
124 }
125
cc61c64b 126 #[inline]
dfeec247 127 pub fn while_hashing_hir_bodies<F: FnOnce(&mut Self)>(&mut self, hash_bodies: bool, f: F) {
cc61c64b
XL
128 let prev_hash_bodies = self.hash_bodies;
129 self.hash_bodies = hash_bodies;
130 f(self);
131 self.hash_bodies = prev_hash_bodies;
132 }
133
134 #[inline]
dfeec247 135 pub fn while_hashing_spans<F: FnOnce(&mut Self)>(&mut self, hash_spans: bool, f: F) {
cc61c64b
XL
136 let prev_hash_spans = self.hash_spans;
137 self.hash_spans = hash_spans;
138 f(self);
139 self.hash_spans = prev_hash_spans;
140 }
141
142 #[inline]
dfeec247
XL
143 pub fn with_node_id_hashing_mode<F: FnOnce(&mut Self)>(
144 &mut self,
145 mode: NodeIdHashingMode,
146 f: F,
147 ) {
cc61c64b
XL
148 let prev = self.node_id_hashing_mode;
149 self.node_id_hashing_mode = mode;
150 f(self);
151 self.node_id_hashing_mode = prev;
152 }
153
154 #[inline]
ea8adc8c 155 pub fn def_path_hash(&self, def_id: DefId) -> DefPathHash {
ba9703b0
XL
156 if let Some(def_id) = def_id.as_local() {
157 self.local_def_path_hash(def_id)
ea8adc8c
XL
158 } else {
159 self.cstore.def_path_hash(def_id)
160 }
161 }
162
163 #[inline]
ba9703b0
XL
164 pub fn local_def_path_hash(&self, def_id: LocalDefId) -> DefPathHash {
165 self.definitions.def_path_hash(def_id)
cc61c64b
XL
166 }
167
cc61c64b
XL
168 #[inline]
169 pub fn hash_bodies(&self) -> bool {
170 self.hash_bodies
171 }
172
173 #[inline]
b7449926
XL
174 pub fn source_map(&mut self) -> &mut CachingSourceMapView<'a> {
175 match self.caching_source_map {
74b04a01 176 Some(ref mut sm) => sm,
ea8adc8c 177 ref mut none => {
b7449926 178 *none = Some(CachingSourceMapView::new(self.raw_source_map));
ea8adc8c
XL
179 none.as_mut().unwrap()
180 }
181 }
cc61c64b
XL
182 }
183
184 #[inline]
185 pub fn is_ignored_attr(&self, name: Symbol) -> bool {
b7449926
XL
186 thread_local! {
187 static IGNORED_ATTRIBUTES: FxHashSet<Symbol> = compute_ignored_attr_names();
188 }
189 IGNORED_ATTRIBUTES.with(|attrs| attrs.contains(&name))
cc61c64b 190 }
cc61c64b
XL
191}
192
0531ce1d
XL
193/// Something that can provide a stable hashing context.
194pub trait StableHashingContextProvider<'a> {
195 fn get_stable_hashing_context(&self) -> StableHashingContext<'a>;
196}
197
dfeec247 198impl<'a, 'b, T: StableHashingContextProvider<'a>> StableHashingContextProvider<'a> for &'b T {
0531ce1d
XL
199 fn get_stable_hashing_context(&self) -> StableHashingContext<'a> {
200 (**self).get_stable_hashing_context()
201 }
202}
203
dfeec247 204impl<'a, 'b, T: StableHashingContextProvider<'a>> StableHashingContextProvider<'a> for &'b mut T {
0531ce1d
XL
205 fn get_stable_hashing_context(&self) -> StableHashingContext<'a> {
206 (**self).get_stable_hashing_context()
ea8adc8c
XL
207 }
208}
209
dc9dc135
XL
210impl StableHashingContextProvider<'tcx> for TyCtxt<'tcx> {
211 fn get_stable_hashing_context(&self) -> StableHashingContext<'tcx> {
0531ce1d
XL
212 (*self).create_stable_hashing_context()
213 }
214}
ea8adc8c 215
0531ce1d
XL
216impl<'a> StableHashingContextProvider<'a> for StableHashingContext<'a> {
217 fn get_stable_hashing_context(&self) -> StableHashingContext<'a> {
ea8adc8c
XL
218 self.clone()
219 }
220}
221
0531ce1d 222impl<'a> HashStable<StableHashingContext<'a>> for ast::NodeId {
74b04a01
XL
223 fn hash_stable(&self, _: &mut StableHashingContext<'a>, _: &mut StableHasher) {
224 panic!("Node IDs should not appear in incremental state");
ea8adc8c
XL
225 }
226}
227
dfeec247 228impl<'a> rustc_span::HashStableContext for StableHashingContext<'a> {
60c5eb7d
XL
229 fn hash_spans(&self) -> bool {
230 self.hash_spans
cc61c64b 231 }
cc61c64b 232
3dfed10e
XL
233 #[inline]
234 fn hash_crate_num(&mut self, cnum: CrateNum, hasher: &mut StableHasher) {
235 let hcx = self;
236 hcx.def_path_hash(DefId { krate: cnum, index: CRATE_DEF_INDEX }).hash_stable(hcx, hasher);
237 }
238
74b04a01
XL
239 #[inline]
240 fn hash_def_id(&mut self, def_id: DefId, hasher: &mut StableHasher) {
241 let hcx = self;
242 hcx.def_path_hash(def_id).hash_stable(hcx, hasher);
243 }
244
dfeec247
XL
245 fn byte_pos_to_line_and_col(
246 &mut self,
247 byte: BytePos,
248 ) -> Option<(Lrc<SourceFile>, usize, BytePos)> {
60c5eb7d 249 self.source_map().byte_pos_to_line_and_col(byte)
b7449926
XL
250 }
251}
252
e74abb32 253pub fn hash_stable_trait_impls<'a>(
0531ce1d 254 hcx: &mut StableHashingContext<'a>,
e74abb32 255 hasher: &mut StableHasher,
8faf50e0 256 blanket_impls: &[DefId],
dc9dc135 257 non_blanket_impls: &FxHashMap<fast_reject::SimplifiedType, Vec<DefId>>,
e74abb32 258) {
ea8adc8c 259 {
dfeec247
XL
260 let mut blanket_impls: SmallVec<[_; 8]> =
261 blanket_impls.iter().map(|&def_id| hcx.def_path_hash(def_id)).collect();
cc61c64b 262
ea8adc8c
XL
263 if blanket_impls.len() > 1 {
264 blanket_impls.sort_unstable();
265 }
7cac9316 266
ea8adc8c
XL
267 blanket_impls.hash_stable(hcx, hasher);
268 }
3b2f2976 269
ea8adc8c 270 {
b7449926 271 let mut keys: SmallVec<[_; 8]> =
dfeec247 272 non_blanket_impls.keys().map(|k| (k, k.map_def(|d| hcx.def_path_hash(d)))).collect();
ea8adc8c
XL
273 keys.sort_unstable_by(|&(_, ref k1), &(_, ref k2)| k1.cmp(k2));
274 keys.len().hash_stable(hcx, hasher);
275 for (key, ref stable_key) in keys {
276 stable_key.hash_stable(hcx, hasher);
dfeec247
XL
277 let mut impls: SmallVec<[_; 8]> =
278 non_blanket_impls[key].iter().map(|&impl_id| hcx.def_path_hash(impl_id)).collect();
ea8adc8c
XL
279
280 if impls.len() > 1 {
281 impls.sort_unstable();
282 }
7cac9316 283
ea8adc8c
XL
284 impls.hash_stable(hcx, hasher);
285 }
7cac9316
XL
286 }
287}