rustc_hir/
hir_id.rs

1use std::fmt::{self, Debug};
2
3use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableOrd, ToStableHashKey};
4use rustc_macros::{Decodable, Encodable, HashStable_Generic};
5use rustc_span::HashStableContext;
6use rustc_span::def_id::DefPathHash;
7
8use crate::def_id::{CRATE_DEF_ID, DefId, DefIndex, LocalDefId};
9
10#[derive(Copy, Clone, PartialEq, Eq, Hash, Encodable, Decodable)]
11pub struct OwnerId {
12    pub def_id: LocalDefId,
13}
14
15impl Debug for OwnerId {
16    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
17        // Example: DefId(0:1 ~ aa[7697]::{use#0})
18        Debug::fmt(&self.def_id, f)
19    }
20}
21
22impl From<OwnerId> for HirId {
23    fn from(owner: OwnerId) -> HirId {
24        HirId { owner, local_id: ItemLocalId::ZERO }
25    }
26}
27
28impl From<OwnerId> for DefId {
29    fn from(value: OwnerId) -> Self {
30        value.to_def_id()
31    }
32}
33
34impl OwnerId {
35    #[inline]
36    pub fn to_def_id(self) -> DefId {
37        self.def_id.to_def_id()
38    }
39}
40
41impl rustc_index::Idx for OwnerId {
42    #[inline]
43    fn new(idx: usize) -> Self {
44        OwnerId { def_id: LocalDefId { local_def_index: DefIndex::from_usize(idx) } }
45    }
46
47    #[inline]
48    fn index(self) -> usize {
49        self.def_id.local_def_index.as_usize()
50    }
51}
52
53impl<CTX: HashStableContext> HashStable<CTX> for OwnerId {
54    #[inline]
55    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
56        self.to_stable_hash_key(hcx).hash_stable(hcx, hasher);
57    }
58}
59
60impl<CTX: HashStableContext> ToStableHashKey<CTX> for OwnerId {
61    type KeyType = DefPathHash;
62
63    #[inline]
64    fn to_stable_hash_key(&self, hcx: &CTX) -> DefPathHash {
65        hcx.def_path_hash(self.to_def_id())
66    }
67}
68
69/// Uniquely identifies a node in the HIR of the current crate. It is
70/// composed of the `owner`, which is the `LocalDefId` of the directly enclosing
71/// `hir::Item`, `hir::TraitItem`, or `hir::ImplItem` (i.e., the closest "item-like"),
72/// and the `local_id` which is unique within the given owner.
73///
74/// This two-level structure makes for more stable values: One can move an item
75/// around within the source code, or add or remove stuff before it, without
76/// the `local_id` part of the `HirId` changing, which is a very useful property in
77/// incremental compilation where we have to persist things through changes to
78/// the code base.
79#[derive(Copy, Clone, PartialEq, Eq, Hash, Encodable, Decodable, HashStable_Generic)]
80#[rustc_pass_by_value]
81pub struct HirId {
82    pub owner: OwnerId,
83    pub local_id: ItemLocalId,
84}
85
86// To ensure correctness of incremental compilation,
87// `HirId` must not implement `Ord` or `PartialOrd`.
88// See https://github.com/rust-lang/rust/issues/90317.
89impl !Ord for HirId {}
90impl !PartialOrd for HirId {}
91
92impl Debug for HirId {
93    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94        // Example: HirId(DefId(0:1 ~ aa[7697]::{use#0}).10)
95        // Don't use debug_tuple to always keep this on one line.
96        write!(f, "HirId({:?}.{:?})", self.owner, self.local_id)
97    }
98}
99
100impl HirId {
101    /// Signal local id which should never be used.
102    pub const INVALID: HirId =
103        HirId { owner: OwnerId { def_id: CRATE_DEF_ID }, local_id: ItemLocalId::INVALID };
104
105    #[inline]
106    pub fn expect_owner(self) -> OwnerId {
107        assert_eq!(self.local_id.index(), 0);
108        self.owner
109    }
110
111    #[inline]
112    pub fn as_owner(self) -> Option<OwnerId> {
113        if self.local_id.index() == 0 { Some(self.owner) } else { None }
114    }
115
116    #[inline]
117    pub fn is_owner(self) -> bool {
118        self.local_id.index() == 0
119    }
120
121    #[inline]
122    pub fn make_owner(owner: LocalDefId) -> Self {
123        Self { owner: OwnerId { def_id: owner }, local_id: ItemLocalId::ZERO }
124    }
125}
126
127impl fmt::Display for HirId {
128    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
129        write!(f, "{self:?}")
130    }
131}
132
133rustc_data_structures::define_stable_id_collections!(HirIdMap, HirIdSet, HirIdMapEntry, HirId);
134rustc_data_structures::define_id_collections!(
135    ItemLocalMap,
136    ItemLocalSet,
137    ItemLocalMapEntry,
138    ItemLocalId
139);
140
141rustc_index::newtype_index! {
142    /// An `ItemLocalId` uniquely identifies something within a given "item-like";
143    /// that is, within a `hir::Item`, `hir::TraitItem`, or `hir::ImplItem`. There is no
144    /// guarantee that the numerical value of a given `ItemLocalId` corresponds to
145    /// the node's position within the owning item in any way, but there is a
146    /// guarantee that the `ItemLocalId`s within an owner occupy a dense range of
147    /// integers starting at zero, so a mapping that maps all or most nodes within
148    /// an "item-like" to something else can be implemented by a `Vec` instead of a
149    /// tree or hash map.
150    #[derive(HashStable_Generic)]
151    #[encodable]
152    #[orderable]
153    pub struct ItemLocalId {}
154}
155
156impl ItemLocalId {
157    /// Signal local id which should never be used.
158    pub const INVALID: ItemLocalId = ItemLocalId::MAX;
159}
160
161impl StableOrd for ItemLocalId {
162    const CAN_USE_UNSTABLE_SORT: bool = true;
163
164    // `Ord` is implemented as just comparing the ItemLocalId's numerical
165    // values and these are not changed by (de-)serialization.
166    const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED: () = ();
167}
168
169/// The `HirId` corresponding to `CRATE_NODE_ID` and `CRATE_DEF_ID`.
170pub const CRATE_HIR_ID: HirId =
171    HirId { owner: OwnerId { def_id: CRATE_DEF_ID }, local_id: ItemLocalId::ZERO };
172
173pub const CRATE_OWNER_ID: OwnerId = OwnerId { def_id: CRATE_DEF_ID };