]>
Commit | Line | Data |
---|---|---|
ba9703b0 | 1 | use crate::def_id::{LocalDefId, CRATE_DEF_INDEX}; |
6a06907d | 2 | use rustc_index::vec::IndexVec; |
dfeec247 XL |
3 | use std::fmt; |
4 | ||
5 | /// Uniquely identifies a node in the HIR of the current crate. It is | |
ba9703b0 | 6 | /// composed of the `owner`, which is the `LocalDefId` of the directly enclosing |
dfeec247 XL |
7 | /// `hir::Item`, `hir::TraitItem`, or `hir::ImplItem` (i.e., the closest "item-like"), |
8 | /// and the `local_id` which is unique within the given owner. | |
9 | /// | |
10 | /// This two-level structure makes for more stable values: One can move an item | |
11 | /// around within the source code, or add or remove stuff before it, without | |
12 | /// the `local_id` part of the `HirId` changing, which is a very useful property in | |
13 | /// incremental compilation where we have to persist things through changes to | |
14 | /// the code base. | |
3dfed10e XL |
15 | #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)] |
16 | #[derive(Encodable, Decodable)] | |
dfeec247 | 17 | pub struct HirId { |
ba9703b0 | 18 | pub owner: LocalDefId, |
dfeec247 XL |
19 | pub local_id: ItemLocalId, |
20 | } | |
21 | ||
6a06907d XL |
22 | impl HirId { |
23 | pub fn expect_owner(self) -> LocalDefId { | |
24 | assert_eq!(self.local_id.index(), 0); | |
25 | self.owner | |
26 | } | |
27 | ||
28 | pub fn as_owner(self) -> Option<LocalDefId> { | |
29 | if self.local_id.index() == 0 { Some(self.owner) } else { None } | |
30 | } | |
31 | ||
32 | #[inline] | |
33 | pub fn make_owner(owner: LocalDefId) -> Self { | |
34 | Self { owner, local_id: ItemLocalId::from_u32(0) } | |
35 | } | |
36 | } | |
37 | ||
dfeec247 XL |
38 | impl fmt::Display for HirId { |
39 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
40 | write!(f, "{:?}", self) | |
41 | } | |
42 | } | |
43 | ||
44 | rustc_data_structures::define_id_collections!(HirIdMap, HirIdSet, HirId); | |
45 | rustc_data_structures::define_id_collections!(ItemLocalMap, ItemLocalSet, ItemLocalId); | |
46 | ||
47 | rustc_index::newtype_index! { | |
48 | /// An `ItemLocalId` uniquely identifies something within a given "item-like"; | |
49 | /// that is, within a `hir::Item`, `hir::TraitItem`, or `hir::ImplItem`. There is no | |
50 | /// guarantee that the numerical value of a given `ItemLocalId` corresponds to | |
51 | /// the node's position within the owning item in any way, but there is a | |
52 | /// guarantee that the `LocalItemId`s within an owner occupy a dense range of | |
53 | /// integers starting at zero, so a mapping that maps all or most nodes within | |
54 | /// an "item-like" to something else can be implemented by a `Vec` instead of a | |
55 | /// tree or hash map. | |
56 | pub struct ItemLocalId { .. } | |
57 | } | |
58 | rustc_data_structures::impl_stable_hash_via_hash!(ItemLocalId); | |
59 | ||
60 | /// The `HirId` corresponding to `CRATE_NODE_ID` and `CRATE_DEF_INDEX`. | |
ba9703b0 XL |
61 | pub const CRATE_HIR_ID: HirId = HirId { |
62 | owner: LocalDefId { local_def_index: CRATE_DEF_INDEX }, | |
63 | local_id: ItemLocalId::from_u32(0), | |
64 | }; | |
6a06907d XL |
65 | |
66 | #[derive(Clone, Default, Debug, Encodable, Decodable)] | |
67 | pub struct HirIdVec<T> { | |
68 | map: IndexVec<LocalDefId, IndexVec<ItemLocalId, T>>, | |
69 | } | |
70 | ||
71 | impl<T> HirIdVec<T> { | |
72 | pub fn push_owner(&mut self, id: LocalDefId) { | |
73 | self.map.ensure_contains_elem(id, IndexVec::new); | |
74 | } | |
75 | ||
76 | pub fn push(&mut self, id: HirId, value: T) { | |
77 | if id.local_id == ItemLocalId::from_u32(0) { | |
78 | self.push_owner(id.owner); | |
79 | } | |
80 | let submap = &mut self.map[id.owner]; | |
81 | let _ret_id = submap.push(value); | |
82 | debug_assert_eq!(_ret_id, id.local_id); | |
83 | } | |
84 | ||
85 | pub fn push_sparse(&mut self, id: HirId, value: T) | |
86 | where | |
87 | T: Default, | |
88 | { | |
89 | self.map.ensure_contains_elem(id.owner, IndexVec::new); | |
90 | let submap = &mut self.map[id.owner]; | |
91 | let i = id.local_id.index(); | |
92 | let len = submap.len(); | |
93 | if i >= len { | |
94 | submap.extend(std::iter::repeat_with(T::default).take(i - len + 1)); | |
95 | } | |
96 | submap[id.local_id] = value; | |
97 | } | |
98 | ||
99 | pub fn get(&self, id: HirId) -> Option<&T> { | |
100 | self.map.get(id.owner)?.get(id.local_id) | |
101 | } | |
102 | ||
103 | pub fn get_owner(&self, id: LocalDefId) -> &IndexVec<ItemLocalId, T> { | |
104 | &self.map[id] | |
105 | } | |
106 | ||
107 | pub fn iter(&self) -> impl Iterator<Item = &T> { | |
108 | self.map.iter().flat_map(|la| la.iter()) | |
109 | } | |
110 | ||
111 | pub fn iter_enumerated(&self) -> impl Iterator<Item = (HirId, &T)> { | |
112 | self.map.iter_enumerated().flat_map(|(owner, la)| { | |
113 | la.iter_enumerated().map(move |(local_id, attr)| (HirId { owner, local_id }, attr)) | |
114 | }) | |
115 | } | |
116 | } | |
117 | ||
118 | impl<T> std::ops::Index<HirId> for HirIdVec<T> { | |
119 | type Output = T; | |
120 | ||
121 | fn index(&self, id: HirId) -> &T { | |
122 | &self.map[id.owner][id.local_id] | |
123 | } | |
124 | } | |
125 | ||
126 | impl<T> std::ops::IndexMut<HirId> for HirIdVec<T> { | |
127 | fn index_mut(&mut self, id: HirId) -> &mut T { | |
128 | &mut self.map[id.owner][id.local_id] | |
129 | } | |
130 | } |