]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_query_system/src/ich/hcx.rs
Rollup merge of #92917 - jackh726:issue-91762-2, r=nikomatsakis
[rust.git] / compiler / rustc_query_system / src / ich / hcx.rs
1 use crate::ich;
2 use rustc_ast as ast;
3 use rustc_data_structures::fx::FxHashSet;
4 use rustc_data_structures::sorted_map::SortedMap;
5 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
6 use rustc_data_structures::stable_hasher::{HashingControls, NodeIdHashingMode};
7 use rustc_data_structures::sync::Lrc;
8 use rustc_hir as hir;
9 use rustc_hir::def_id::{DefId, LocalDefId};
10 use rustc_hir::definitions::{DefPathHash, Definitions};
11 use rustc_session::cstore::CrateStore;
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, Span, SpanData};
16
17 fn compute_ignored_attr_names() -> FxHashSet<Symbol> {
18     debug_assert!(!ich::IGNORED_ATTRIBUTES.is_empty());
19     ich::IGNORED_ATTRIBUTES.iter().copied().collect()
20 }
21
22 /// This is the context state available during incr. comp. hashing. It contains
23 /// enough information to transform `DefId`s and `HirId`s into stable `DefPath`s (i.e.,
24 /// a reference to the `TyCtxt`) and it holds a few caches for speeding up various
25 /// things (e.g., each `DefId`/`DefPath` is only hashed once).
26 #[derive(Clone)]
27 pub struct StableHashingContext<'a> {
28     definitions: &'a Definitions,
29     cstore: &'a dyn CrateStore,
30     // The value of `-Z incremental-ignore-spans`.
31     // This field should only be used by `debug_opts_incremental_ignore_span`
32     incremental_ignore_spans: bool,
33     pub(super) body_resolver: BodyResolver<'a>,
34     // Very often, we are hashing something that does not need the
35     // `CachingSourceMapView`, so we initialize it lazily.
36     raw_source_map: &'a SourceMap,
37     caching_source_map: Option<CachingSourceMapView<'a>>,
38     pub(super) hashing_controls: HashingControls,
39 }
40
41 /// The `BodyResolver` allows mapping a `BodyId` to the corresponding `hir::Body`.
42 /// We could also just store a plain reference to the `hir::Crate` but we want
43 /// to avoid that the crate is used to get untracked access to all of the HIR.
44 #[derive(Clone, Copy)]
45 pub(super) enum BodyResolver<'tcx> {
46     Forbidden,
47     Traverse {
48         hash_bodies: bool,
49         owner: LocalDefId,
50         bodies: &'tcx SortedMap<hir::ItemLocalId, &'tcx hir::Body<'tcx>>,
51     },
52 }
53
54 impl<'a> StableHashingContext<'a> {
55     #[inline]
56     fn new_with_or_without_spans(
57         sess: &'a Session,
58         definitions: &'a Definitions,
59         cstore: &'a dyn CrateStore,
60         always_ignore_spans: bool,
61     ) -> Self {
62         let hash_spans_initial =
63             !always_ignore_spans && !sess.opts.debugging_opts.incremental_ignore_spans;
64
65         StableHashingContext {
66             body_resolver: BodyResolver::Forbidden,
67             definitions,
68             cstore,
69             incremental_ignore_spans: sess.opts.debugging_opts.incremental_ignore_spans,
70             caching_source_map: None,
71             raw_source_map: sess.source_map(),
72             hashing_controls: HashingControls {
73                 hash_spans: hash_spans_initial,
74                 node_id_hashing_mode: NodeIdHashingMode::HashDefPath,
75             },
76         }
77     }
78
79     #[inline]
80     pub fn new(
81         sess: &'a Session,
82         definitions: &'a Definitions,
83         cstore: &'a dyn CrateStore,
84     ) -> Self {
85         Self::new_with_or_without_spans(
86             sess,
87             definitions,
88             cstore,
89             /*always_ignore_spans=*/ false,
90         )
91     }
92
93     #[inline]
94     pub fn ignore_spans(
95         sess: &'a Session,
96         definitions: &'a Definitions,
97         cstore: &'a dyn CrateStore,
98     ) -> Self {
99         let always_ignore_spans = true;
100         Self::new_with_or_without_spans(sess, definitions, cstore, always_ignore_spans)
101     }
102
103     /// Allow hashing
104     #[inline]
105     pub fn while_hashing_hir_bodies(&mut self, hb: bool, f: impl FnOnce(&mut Self)) {
106         let prev = match &mut self.body_resolver {
107             BodyResolver::Forbidden => panic!("Hashing HIR bodies is forbidden."),
108             BodyResolver::Traverse { ref mut hash_bodies, .. } => {
109                 std::mem::replace(hash_bodies, hb)
110             }
111         };
112         f(self);
113         match &mut self.body_resolver {
114             BodyResolver::Forbidden => unreachable!(),
115             BodyResolver::Traverse { ref mut hash_bodies, .. } => *hash_bodies = prev,
116         }
117     }
118
119     #[inline]
120     pub fn with_hir_bodies(
121         &mut self,
122         hash_bodies: bool,
123         owner: LocalDefId,
124         bodies: &'a SortedMap<hir::ItemLocalId, &'a hir::Body<'a>>,
125         f: impl FnOnce(&mut Self),
126     ) {
127         let prev = self.body_resolver;
128         self.body_resolver = BodyResolver::Traverse { hash_bodies, owner, bodies };
129         f(self);
130         self.body_resolver = prev;
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.hashing_controls.hash_spans;
136         self.hashing_controls.hash_spans = hash_spans;
137         f(self);
138         self.hashing_controls.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.hashing_controls.node_id_hashing_mode;
148         self.hashing_controls.node_id_hashing_mode = mode;
149         f(self);
150         self.hashing_controls.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 source_map(&mut self) -> &mut CachingSourceMapView<'a> {
169         match self.caching_source_map {
170             Some(ref mut sm) => sm,
171             ref mut none => {
172                 *none = Some(CachingSourceMapView::new(self.raw_source_map));
173                 none.as_mut().unwrap()
174             }
175         }
176     }
177
178     #[inline]
179     pub fn is_ignored_attr(&self, name: Symbol) -> bool {
180         thread_local! {
181             static IGNORED_ATTRIBUTES: FxHashSet<Symbol> = compute_ignored_attr_names();
182         }
183         IGNORED_ATTRIBUTES.with(|attrs| attrs.contains(&name))
184     }
185
186     #[inline]
187     pub fn hashing_controls(&self) -> HashingControls {
188         self.hashing_controls.clone()
189     }
190 }
191
192 impl<'a> HashStable<StableHashingContext<'a>> for ast::NodeId {
193     #[inline]
194     fn hash_stable(&self, _: &mut StableHashingContext<'a>, _: &mut StableHasher) {
195         panic!("Node IDs should not appear in incremental state");
196     }
197 }
198
199 impl<'a> rustc_span::HashStableContext for StableHashingContext<'a> {
200     #[inline]
201     fn hash_spans(&self) -> bool {
202         self.hashing_controls.hash_spans
203     }
204
205     #[inline]
206     fn debug_opts_incremental_ignore_spans(&self) -> bool {
207         self.incremental_ignore_spans
208     }
209
210     #[inline]
211     fn def_path_hash(&self, def_id: DefId) -> DefPathHash {
212         self.def_path_hash(def_id)
213     }
214
215     #[inline]
216     fn def_span(&self, def_id: LocalDefId) -> Span {
217         self.definitions.def_span(def_id)
218     }
219
220     #[inline]
221     fn span_data_to_lines_and_cols(
222         &mut self,
223         span: &SpanData,
224     ) -> Option<(Lrc<SourceFile>, usize, BytePos, usize, BytePos)> {
225         self.source_map().span_data_to_lines_and_cols(span)
226     }
227
228     #[inline]
229     fn hashing_controls(&self) -> HashingControls {
230         self.hashing_controls.clone()
231     }
232 }
233
234 impl<'a> rustc_session::HashStableContext for StableHashingContext<'a> {}