]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_middle/src/hir/map/collector.rs
Forbid hashing HIR outside of indexing.
[rust.git] / compiler / rustc_middle / src / hir / map / collector.rs
1 use crate::arena::Arena;
2 use crate::hir::map::Map;
3 use crate::hir::{IndexedHir, OwnerNodes, ParentedNode};
4 use rustc_data_structures::fingerprint::Fingerprint;
5 use rustc_data_structures::fx::FxHashMap;
6 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
7 use rustc_hir as hir;
8 use rustc_hir::def_id::LocalDefId;
9 use rustc_hir::def_id::CRATE_DEF_ID;
10 use rustc_hir::definitions;
11 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
12 use rustc_hir::*;
13 use rustc_index::vec::{Idx, IndexVec};
14 use rustc_query_system::ich::StableHashingContext;
15 use rustc_session::Session;
16 use rustc_span::source_map::SourceMap;
17 use rustc_span::{Span, DUMMY_SP};
18
19 use std::iter::repeat;
20
21 /// A visitor that walks over the HIR and collects `Node`s into a HIR map.
22 pub(super) struct NodeCollector<'a, 'hir> {
23     arena: &'hir Arena<'hir>,
24
25     /// The crate
26     krate: &'hir Crate<'hir>,
27
28     /// Source map
29     source_map: &'a SourceMap,
30
31     map: IndexVec<LocalDefId, Option<&'hir mut OwnerNodes<'hir>>>,
32     parenting: FxHashMap<LocalDefId, HirId>,
33
34     /// The parent of this node
35     parent_node: hir::HirId,
36
37     current_dep_node_owner: LocalDefId,
38
39     definitions: &'a definitions::Definitions,
40
41     hcx: StableHashingContext<'a>,
42 }
43
44 fn insert_vec_map<K: Idx, V: Clone>(map: &mut IndexVec<K, Option<V>>, k: K, v: V) {
45     let i = k.index();
46     let len = map.len();
47     if i >= len {
48         map.extend(repeat(None).take(i - len + 1));
49     }
50     debug_assert!(map[k].is_none());
51     map[k] = Some(v);
52 }
53
54 fn hash_body<'s, 'hir: 's>(
55     hcx: &mut StableHashingContext<'s>,
56     item_like: impl for<'a> HashStable<StableHashingContext<'a>>,
57     hash_bodies: bool,
58     owner: LocalDefId,
59     bodies: &'hir IndexVec<ItemLocalId, Option<&'hir Body<'hir>>>,
60 ) -> Fingerprint {
61     let mut stable_hasher = StableHasher::new();
62     hcx.with_hir_bodies(hash_bodies, owner, bodies, |hcx| {
63         item_like.hash_stable(hcx, &mut stable_hasher)
64     });
65     stable_hasher.finish()
66 }
67
68 impl<'a, 'hir: 'a> NodeCollector<'a, 'hir> {
69     pub(super) fn root(
70         sess: &'a Session,
71         arena: &'hir Arena<'hir>,
72         krate: &'hir Crate<'hir>,
73         definitions: &'a definitions::Definitions,
74         hcx: StableHashingContext<'a>,
75     ) -> NodeCollector<'a, 'hir> {
76         let mut collector = NodeCollector {
77             arena,
78             krate,
79             source_map: sess.source_map(),
80             parent_node: hir::CRATE_HIR_ID,
81             current_dep_node_owner: CRATE_DEF_ID,
82             definitions,
83             hcx,
84             map: IndexVec::from_fn_n(|_| None, definitions.def_index_count()),
85             parenting: FxHashMap::default(),
86         };
87         collector.insert_owner(CRATE_DEF_ID, OwnerNode::Crate(krate.module()));
88
89         collector
90     }
91
92     pub(super) fn finalize_and_compute_crate_hash(self) -> IndexedHir<'hir> {
93         IndexedHir { map: self.map, parenting: self.parenting }
94     }
95
96     fn insert_owner(&mut self, owner: LocalDefId, node: OwnerNode<'hir>) {
97         let mut nodes = IndexVec::new();
98         nodes.push(Some(ParentedNode { parent: ItemLocalId::new(0), node: node.into() }));
99
100         let bodies = &self.krate.owners[owner].as_ref().unwrap().bodies;
101
102         let hash = hash_body(&mut self.hcx, node, true, owner, bodies);
103         let node_hash = hash_body(&mut self.hcx, node, false, owner, bodies);
104
105         debug_assert!(self.map[owner].is_none());
106         self.map[owner] = Some(self.arena.alloc(OwnerNodes { hash, node_hash, nodes, bodies }));
107     }
108
109     fn insert(&mut self, span: Span, hir_id: HirId, node: Node<'hir>) {
110         debug_assert_eq!(self.current_dep_node_owner, hir_id.owner);
111         debug_assert_ne!(hir_id.local_id.as_u32(), 0);
112
113         // Make sure that the DepNode of some node coincides with the HirId
114         // owner of that node.
115         if cfg!(debug_assertions) {
116             if hir_id.owner != self.current_dep_node_owner {
117                 let node_str = match self.definitions.opt_hir_id_to_local_def_id(hir_id) {
118                     Some(def_id) => self.definitions.def_path(def_id).to_string_no_crate_verbose(),
119                     None => format!("{:?}", node),
120                 };
121
122                 span_bug!(
123                     span,
124                     "inconsistent DepNode at `{:?}` for `{}`: \
125                      current_dep_node_owner={} ({:?}), hir_id.owner={} ({:?})",
126                     self.source_map.span_to_diagnostic_string(span),
127                     node_str,
128                     self.definitions
129                         .def_path(self.current_dep_node_owner)
130                         .to_string_no_crate_verbose(),
131                     self.current_dep_node_owner,
132                     self.definitions.def_path(hir_id.owner).to_string_no_crate_verbose(),
133                     hir_id.owner,
134                 )
135             }
136         }
137
138         let nodes = self.map[hir_id.owner].as_mut().unwrap();
139
140         debug_assert_eq!(self.parent_node.owner, self.current_dep_node_owner);
141         insert_vec_map(
142             &mut nodes.nodes,
143             hir_id.local_id,
144             ParentedNode { parent: self.parent_node.local_id, node: node },
145         );
146     }
147
148     fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_node_id: HirId, f: F) {
149         let parent_node = self.parent_node;
150         self.parent_node = parent_node_id;
151         f(self);
152         self.parent_node = parent_node;
153     }
154
155     fn with_dep_node_owner(&mut self, dep_node_owner: LocalDefId, f: impl FnOnce(&mut Self)) {
156         let prev_owner = self.current_dep_node_owner;
157         let prev_parent = self.parent_node;
158
159         self.current_dep_node_owner = dep_node_owner;
160         self.parent_node = HirId::make_owner(dep_node_owner);
161         f(self);
162         self.current_dep_node_owner = prev_owner;
163         self.parent_node = prev_parent;
164     }
165
166     fn insert_nested(&mut self, item: LocalDefId) {
167         #[cfg(debug_assertions)]
168         {
169             let dk_parent = self.definitions.def_key(item).parent.unwrap();
170             let dk_parent = LocalDefId { local_def_index: dk_parent };
171             let dk_parent = self.definitions.local_def_id_to_hir_id(dk_parent);
172             debug_assert_eq!(
173                 dk_parent.owner, self.parent_node.owner,
174                 "Different parents for {:?}",
175                 item
176             )
177         }
178
179         assert_eq!(self.parenting.insert(item, self.parent_node), None);
180     }
181 }
182
183 impl<'a, 'hir: 'a> Visitor<'hir> for NodeCollector<'a, 'hir> {
184     type Map = Map<'hir>;
185
186     /// Because we want to track parent items and so forth, enable
187     /// deep walking so that we walk nested items in the context of
188     /// their outer items.
189
190     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
191         panic!("`visit_nested_xxx` must be manually implemented in this visitor");
192     }
193
194     fn visit_nested_item(&mut self, item: ItemId) {
195         debug!("visit_nested_item: {:?}", item);
196         self.insert_nested(item.def_id);
197         self.visit_item(self.krate.item(item));
198     }
199
200     fn visit_nested_trait_item(&mut self, item_id: TraitItemId) {
201         self.insert_nested(item_id.def_id);
202         self.visit_trait_item(self.krate.trait_item(item_id));
203     }
204
205     fn visit_nested_impl_item(&mut self, item_id: ImplItemId) {
206         self.insert_nested(item_id.def_id);
207         self.visit_impl_item(self.krate.impl_item(item_id));
208     }
209
210     fn visit_nested_foreign_item(&mut self, foreign_id: ForeignItemId) {
211         self.insert_nested(foreign_id.def_id);
212         self.visit_foreign_item(self.krate.foreign_item(foreign_id));
213     }
214
215     fn visit_nested_body(&mut self, id: BodyId) {
216         self.visit_body(self.krate.body(id));
217     }
218
219     fn visit_param(&mut self, param: &'hir Param<'hir>) {
220         let node = Node::Param(param);
221         self.insert(param.pat.span, param.hir_id, node);
222         self.with_parent(param.hir_id, |this| {
223             intravisit::walk_param(this, param);
224         });
225     }
226
227     fn visit_item(&mut self, i: &'hir Item<'hir>) {
228         debug!("visit_item: {:?}", i);
229         self.insert_owner(i.def_id, OwnerNode::Item(i));
230         self.with_dep_node_owner(i.def_id, |this| {
231             if let ItemKind::Struct(ref struct_def, _) = i.kind {
232                 // If this is a tuple or unit-like struct, register the constructor.
233                 if let Some(ctor_hir_id) = struct_def.ctor_hir_id() {
234                     this.insert(i.span, ctor_hir_id, Node::Ctor(struct_def));
235                 }
236             }
237             intravisit::walk_item(this, i);
238         });
239     }
240
241     fn visit_foreign_item(&mut self, fi: &'hir ForeignItem<'hir>) {
242         self.insert_owner(fi.def_id, OwnerNode::ForeignItem(fi));
243         self.with_dep_node_owner(fi.def_id, |this| {
244             intravisit::walk_foreign_item(this, fi);
245         });
246     }
247
248     fn visit_generic_param(&mut self, param: &'hir GenericParam<'hir>) {
249         self.insert(param.span, param.hir_id, Node::GenericParam(param));
250         intravisit::walk_generic_param(self, param);
251     }
252
253     fn visit_const_param_default(&mut self, param: HirId, ct: &'hir AnonConst) {
254         self.with_parent(param, |this| {
255             intravisit::walk_const_param_default(this, ct);
256         })
257     }
258
259     fn visit_trait_item(&mut self, ti: &'hir TraitItem<'hir>) {
260         self.insert_owner(ti.def_id, OwnerNode::TraitItem(ti));
261         self.with_dep_node_owner(ti.def_id, |this| {
262             intravisit::walk_trait_item(this, ti);
263         });
264     }
265
266     fn visit_impl_item(&mut self, ii: &'hir ImplItem<'hir>) {
267         self.insert_owner(ii.def_id, OwnerNode::ImplItem(ii));
268         self.with_dep_node_owner(ii.def_id, |this| {
269             intravisit::walk_impl_item(this, ii);
270         });
271     }
272
273     fn visit_pat(&mut self, pat: &'hir Pat<'hir>) {
274         let node =
275             if let PatKind::Binding(..) = pat.kind { Node::Binding(pat) } else { Node::Pat(pat) };
276         self.insert(pat.span, pat.hir_id, node);
277
278         self.with_parent(pat.hir_id, |this| {
279             intravisit::walk_pat(this, pat);
280         });
281     }
282
283     fn visit_arm(&mut self, arm: &'hir Arm<'hir>) {
284         let node = Node::Arm(arm);
285
286         self.insert(arm.span, arm.hir_id, node);
287
288         self.with_parent(arm.hir_id, |this| {
289             intravisit::walk_arm(this, arm);
290         });
291     }
292
293     fn visit_anon_const(&mut self, constant: &'hir AnonConst) {
294         self.insert(DUMMY_SP, constant.hir_id, Node::AnonConst(constant));
295
296         self.with_parent(constant.hir_id, |this| {
297             intravisit::walk_anon_const(this, constant);
298         });
299     }
300
301     fn visit_expr(&mut self, expr: &'hir Expr<'hir>) {
302         self.insert(expr.span, expr.hir_id, Node::Expr(expr));
303
304         self.with_parent(expr.hir_id, |this| {
305             intravisit::walk_expr(this, expr);
306         });
307     }
308
309     fn visit_stmt(&mut self, stmt: &'hir Stmt<'hir>) {
310         self.insert(stmt.span, stmt.hir_id, Node::Stmt(stmt));
311
312         self.with_parent(stmt.hir_id, |this| {
313             intravisit::walk_stmt(this, stmt);
314         });
315     }
316
317     fn visit_path_segment(&mut self, path_span: Span, path_segment: &'hir PathSegment<'hir>) {
318         if let Some(hir_id) = path_segment.hir_id {
319             self.insert(path_span, hir_id, Node::PathSegment(path_segment));
320         }
321         intravisit::walk_path_segment(self, path_span, path_segment);
322     }
323
324     fn visit_ty(&mut self, ty: &'hir Ty<'hir>) {
325         self.insert(ty.span, ty.hir_id, Node::Ty(ty));
326
327         self.with_parent(ty.hir_id, |this| {
328             intravisit::walk_ty(this, ty);
329         });
330     }
331
332     fn visit_infer(&mut self, inf: &'hir InferArg) {
333         self.insert(inf.span, inf.hir_id, Node::Infer(inf));
334
335         self.with_parent(inf.hir_id, |this| {
336             intravisit::walk_inf(this, inf);
337         });
338     }
339
340     fn visit_trait_ref(&mut self, tr: &'hir TraitRef<'hir>) {
341         self.insert(tr.path.span, tr.hir_ref_id, Node::TraitRef(tr));
342
343         self.with_parent(tr.hir_ref_id, |this| {
344             intravisit::walk_trait_ref(this, tr);
345         });
346     }
347
348     fn visit_fn(
349         &mut self,
350         fk: intravisit::FnKind<'hir>,
351         fd: &'hir FnDecl<'hir>,
352         b: BodyId,
353         s: Span,
354         id: HirId,
355     ) {
356         assert_eq!(self.parent_node, id);
357         intravisit::walk_fn(self, fk, fd, b, s, id);
358     }
359
360     fn visit_block(&mut self, block: &'hir Block<'hir>) {
361         self.insert(block.span, block.hir_id, Node::Block(block));
362         self.with_parent(block.hir_id, |this| {
363             intravisit::walk_block(this, block);
364         });
365     }
366
367     fn visit_local(&mut self, l: &'hir Local<'hir>) {
368         self.insert(l.span, l.hir_id, Node::Local(l));
369         self.with_parent(l.hir_id, |this| {
370             intravisit::walk_local(this, l);
371         })
372     }
373
374     fn visit_lifetime(&mut self, lifetime: &'hir Lifetime) {
375         self.insert(lifetime.span, lifetime.hir_id, Node::Lifetime(lifetime));
376     }
377
378     fn visit_vis(&mut self, visibility: &'hir Visibility<'hir>) {
379         match visibility.node {
380             VisibilityKind::Public | VisibilityKind::Crate(_) | VisibilityKind::Inherited => {}
381             VisibilityKind::Restricted { hir_id, .. } => {
382                 self.insert(visibility.span, hir_id, Node::Visibility(visibility));
383                 self.with_parent(hir_id, |this| {
384                     intravisit::walk_vis(this, visibility);
385                 });
386             }
387         }
388     }
389
390     fn visit_variant(&mut self, v: &'hir Variant<'hir>, g: &'hir Generics<'hir>, item_id: HirId) {
391         self.insert(v.span, v.id, Node::Variant(v));
392         self.with_parent(v.id, |this| {
393             // Register the constructor of this variant.
394             if let Some(ctor_hir_id) = v.data.ctor_hir_id() {
395                 this.insert(v.span, ctor_hir_id, Node::Ctor(&v.data));
396             }
397             intravisit::walk_variant(this, v, g, item_id);
398         });
399     }
400
401     fn visit_field_def(&mut self, field: &'hir FieldDef<'hir>) {
402         self.insert(field.span, field.hir_id, Node::Field(field));
403         self.with_parent(field.hir_id, |this| {
404             intravisit::walk_field_def(this, field);
405         });
406     }
407
408     fn visit_trait_item_ref(&mut self, ii: &'hir TraitItemRef) {
409         // Do not visit the duplicate information in TraitItemRef. We want to
410         // map the actual nodes, not the duplicate ones in the *Ref.
411         let TraitItemRef { id, ident: _, kind: _, span: _, defaultness: _ } = *ii;
412
413         self.visit_nested_trait_item(id);
414     }
415
416     fn visit_impl_item_ref(&mut self, ii: &'hir ImplItemRef) {
417         // Do not visit the duplicate information in ImplItemRef. We want to
418         // map the actual nodes, not the duplicate ones in the *Ref.
419         let ImplItemRef { id, ident: _, kind: _, span: _, defaultness: _ } = *ii;
420
421         self.visit_nested_impl_item(id);
422     }
423
424     fn visit_foreign_item_ref(&mut self, fi: &'hir ForeignItemRef) {
425         // Do not visit the duplicate information in ForeignItemRef. We want to
426         // map the actual nodes, not the duplicate ones in the *Ref.
427         let ForeignItemRef { id, ident: _, span: _ } = *fi;
428
429         self.visit_nested_foreign_item(id);
430     }
431 }