|
1 | | -use crate::hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX}; |
2 | | -use crate::hir::{self, intravisit, HirId, ItemLocalId}; |
3 | | -use crate::hir::itemlikevisit::ItemLikeVisitor; |
4 | | -use rustc_data_structures::fx::FxHashSet; |
| 1 | +use crate::hir::def_id::{DefId, DefIndex}; |
| 2 | +use crate::hir::{self, HirId}; |
5 | 3 | use rustc_data_structures::sync::{Lock, ParallelIterator, par_iter}; |
| 4 | +use std::collections::BTreeMap; |
6 | 5 |
|
7 | 6 | pub fn check_crate(hir_map: &hir::map::Map<'_>) { |
8 | 7 | hir_map.dep_graph.assert_ignored(); |
9 | 8 |
|
10 | 9 | let errors = Lock::new(Vec::new()); |
11 | 10 |
|
12 | | - par_iter(&hir_map.krate().modules).for_each(|(module_id, _)| { |
13 | | - let local_def_id = hir_map.local_def_id(*module_id); |
14 | | - hir_map.visit_item_likes_in_module(local_def_id, &mut OuterVisitor { |
15 | | - hir_map, |
16 | | - errors: &errors, |
17 | | - }); |
| 11 | + par_iter(0..hir_map.map.len()).for_each(|owner| { |
| 12 | + let owner = DefIndex::from(owner); |
| 13 | + let local_map = &hir_map.map[owner]; |
| 14 | + |
| 15 | + // Collect the missing `ItemLocalId`s. |
| 16 | + let missing: Vec<_> = local_map |
| 17 | + .iter_enumerated() |
| 18 | + .filter(|(_, entry)| entry.is_none()) |
| 19 | + .map(|(local_id, _)| local_id) |
| 20 | + .collect(); |
| 21 | + |
| 22 | + if !missing.is_empty() { |
| 23 | + let present: BTreeMap<_, _> = local_map |
| 24 | + .iter_enumerated() |
| 25 | + .filter(|(_, entry)| entry.is_some()) |
| 26 | + .map(|(local_id, _)| { |
| 27 | + (local_id, hir_map.node_to_string(HirId { owner, local_id })) |
| 28 | + }) |
| 29 | + .collect(); |
| 30 | + |
| 31 | + errors.lock().push(format!( |
| 32 | + "{}:\n missing IDs = {:?}\n present IDs = {:#?}", |
| 33 | + hir_map.def_path(DefId::local(owner)).to_string_no_crate(), |
| 34 | + missing, |
| 35 | + present, |
| 36 | + )); |
| 37 | + } |
18 | 38 | }); |
19 | 39 |
|
20 | 40 | let errors = errors.into_inner(); |
21 | | - |
22 | 41 | if !errors.is_empty() { |
23 | | - let message = errors |
24 | | - .iter() |
25 | | - .fold(String::new(), |s1, s2| s1 + "\n" + s2); |
26 | | - bug!("{}", message); |
27 | | - } |
28 | | -} |
29 | | - |
30 | | -struct HirIdValidator<'a, 'hir> { |
31 | | - hir_map: &'a hir::map::Map<'hir>, |
32 | | - owner_def_index: Option<DefIndex>, |
33 | | - hir_ids_seen: FxHashSet<ItemLocalId>, |
34 | | - errors: &'a Lock<Vec<String>>, |
35 | | -} |
36 | | - |
37 | | -struct OuterVisitor<'a, 'hir> { |
38 | | - hir_map: &'a hir::map::Map<'hir>, |
39 | | - errors: &'a Lock<Vec<String>>, |
40 | | -} |
41 | | - |
42 | | -impl<'a, 'hir> OuterVisitor<'a, 'hir> { |
43 | | - fn new_inner_visitor(&self, |
44 | | - hir_map: &'a hir::map::Map<'hir>) |
45 | | - -> HirIdValidator<'a, 'hir> { |
46 | | - HirIdValidator { |
47 | | - hir_map, |
48 | | - owner_def_index: None, |
49 | | - hir_ids_seen: Default::default(), |
50 | | - errors: self.errors, |
51 | | - } |
52 | | - } |
53 | | -} |
54 | | - |
55 | | -impl<'a, 'hir> ItemLikeVisitor<'hir> for OuterVisitor<'a, 'hir> { |
56 | | - fn visit_item(&mut self, i: &'hir hir::Item) { |
57 | | - let mut inner_visitor = self.new_inner_visitor(self.hir_map); |
58 | | - inner_visitor.check(i.hir_id, |this| intravisit::walk_item(this, i)); |
59 | | - } |
60 | | - |
61 | | - fn visit_trait_item(&mut self, i: &'hir hir::TraitItem) { |
62 | | - let mut inner_visitor = self.new_inner_visitor(self.hir_map); |
63 | | - inner_visitor.check(i.hir_id, |this| intravisit::walk_trait_item(this, i)); |
64 | | - } |
65 | | - |
66 | | - fn visit_impl_item(&mut self, i: &'hir hir::ImplItem) { |
67 | | - let mut inner_visitor = self.new_inner_visitor(self.hir_map); |
68 | | - inner_visitor.check(i.hir_id, |this| intravisit::walk_impl_item(this, i)); |
69 | | - } |
70 | | -} |
71 | | - |
72 | | -impl<'a, 'hir> HirIdValidator<'a, 'hir> { |
73 | | - #[cold] |
74 | | - #[inline(never)] |
75 | | - fn error(&self, f: impl FnOnce() -> String) { |
76 | | - self.errors.lock().push(f()); |
77 | | - } |
78 | | - |
79 | | - fn check<F: FnOnce(&mut HirIdValidator<'a, 'hir>)>(&mut self, |
80 | | - hir_id: HirId, |
81 | | - walk: F) { |
82 | | - assert!(self.owner_def_index.is_none()); |
83 | | - let owner_def_index = self.hir_map.local_def_id(hir_id).index; |
84 | | - self.owner_def_index = Some(owner_def_index); |
85 | | - walk(self); |
86 | | - |
87 | | - if owner_def_index == CRATE_DEF_INDEX { |
88 | | - return; |
89 | | - } |
90 | | - |
91 | | - // There's always at least one entry for the owning item itself |
92 | | - let max = self.hir_ids_seen |
93 | | - .iter() |
94 | | - .map(|local_id| local_id.as_usize()) |
95 | | - .max() |
96 | | - .expect("owning item has no entry"); |
97 | | - |
98 | | - if max != self.hir_ids_seen.len() - 1 { |
99 | | - // Collect the missing ItemLocalIds |
100 | | - let missing: Vec<_> = (0 ..= max as u32) |
101 | | - .filter(|&i| !self.hir_ids_seen.contains(&ItemLocalId::from_u32(i))) |
102 | | - .collect(); |
103 | | - |
104 | | - // Try to map those to something more useful |
105 | | - let mut missing_items = Vec::with_capacity(missing.len()); |
106 | | - |
107 | | - for local_id in missing { |
108 | | - let hir_id = HirId { |
109 | | - owner: owner_def_index, |
110 | | - local_id: ItemLocalId::from_u32(local_id), |
111 | | - }; |
112 | | - |
113 | | - trace!("missing hir id {:#?}", hir_id); |
114 | | - |
115 | | - missing_items.push(format!("[local_id: {}, node:{}]", |
116 | | - local_id, |
117 | | - self.hir_map.node_to_string(hir_id))); |
118 | | - } |
119 | | - self.error(|| format!( |
120 | | - "ItemLocalIds not assigned densely in {}. \ |
121 | | - Max ItemLocalId = {}, missing IDs = {:?}; seens IDs = {:?}", |
122 | | - self.hir_map.def_path(DefId::local(owner_def_index)).to_string_no_crate(), |
123 | | - max, |
124 | | - missing_items, |
125 | | - self.hir_ids_seen |
126 | | - .iter() |
127 | | - .map(|&local_id| HirId { |
128 | | - owner: owner_def_index, |
129 | | - local_id, |
130 | | - }) |
131 | | - .map(|h| format!("({:?} {})", h, self.hir_map.node_to_string(h))) |
132 | | - .collect::<Vec<_>>())); |
133 | | - } |
134 | | - } |
135 | | -} |
136 | | - |
137 | | -impl<'a, 'hir> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> { |
138 | | - |
139 | | - fn nested_visit_map<'this>(&'this mut self) |
140 | | - -> intravisit::NestedVisitorMap<'this, 'hir> { |
141 | | - intravisit::NestedVisitorMap::OnlyBodies(self.hir_map) |
142 | | - } |
143 | | - |
144 | | - fn visit_id(&mut self, hir_id: HirId) { |
145 | | - let owner = self.owner_def_index.expect("no owner_def_index"); |
146 | | - |
147 | | - if hir_id == hir::DUMMY_HIR_ID { |
148 | | - self.error(|| format!("HirIdValidator: HirId {:?} is invalid", |
149 | | - self.hir_map.node_to_string(hir_id))); |
150 | | - return; |
151 | | - } |
152 | | - |
153 | | - if owner != hir_id.owner { |
154 | | - self.error(|| format!( |
155 | | - "HirIdValidator: The recorded owner of {} is {} instead of {}", |
156 | | - self.hir_map.node_to_string(hir_id), |
157 | | - self.hir_map.def_path(DefId::local(hir_id.owner)).to_string_no_crate(), |
158 | | - self.hir_map.def_path(DefId::local(owner)).to_string_no_crate())); |
159 | | - } |
160 | | - |
161 | | - self.hir_ids_seen.insert(hir_id.local_id); |
162 | | - } |
163 | | - |
164 | | - fn visit_impl_item_ref(&mut self, _: &'hir hir::ImplItemRef) { |
165 | | - // Explicitly do nothing here. ImplItemRefs contain hir::Visibility |
166 | | - // values that actually belong to an ImplItem instead of the ItemKind::Impl |
167 | | - // we are currently in. So for those it's correct that they have a |
168 | | - // different owner. |
| 42 | + bug!("`ItemLocalId`s not assigned densely in:\n{}", errors.join("\n")); |
169 | 43 | } |
170 | 44 | } |
0 commit comments