rustc_hir_id/
lib.rs

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