about summary refs log tree commit diff
path: root/compiler/rustc_hir_id/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_hir_id/src/lib.rs')
-rw-r--r--compiler/rustc_hir_id/src/lib.rs196
1 files changed, 196 insertions, 0 deletions
diff --git a/compiler/rustc_hir_id/src/lib.rs b/compiler/rustc_hir_id/src/lib.rs
new file mode 100644
index 00000000000..d07bc88e66a
--- /dev/null
+++ b/compiler/rustc_hir_id/src/lib.rs
@@ -0,0 +1,196 @@
+//! Library containing Id types from `rustc_hir`, split out so crates can use it without depending
+//! on all of `rustc_hir` (which is large and depends on other large things like `rustc_target`).
+#![allow(internal_features)]
+#![feature(negative_impls)]
+#![feature(rustc_attrs)]
+
+use std::fmt::{self, Debug};
+
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableOrd, ToStableHashKey};
+use rustc_macros::{Decodable, Encodable, HashStable_Generic};
+pub use rustc_span::HashStableContext;
+use rustc_span::def_id::{CRATE_DEF_ID, DefId, DefIndex, DefPathHash, LocalDefId};
+
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Encodable, Decodable)]
+pub struct OwnerId {
+    pub def_id: LocalDefId,
+}
+
+impl Debug for OwnerId {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        // Example: DefId(0:1 ~ aa[7697]::{use#0})
+        Debug::fmt(&self.def_id, f)
+    }
+}
+
+impl From<OwnerId> for HirId {
+    fn from(owner: OwnerId) -> HirId {
+        HirId { owner, local_id: ItemLocalId::ZERO }
+    }
+}
+
+impl From<OwnerId> for DefId {
+    fn from(value: OwnerId) -> Self {
+        value.to_def_id()
+    }
+}
+
+impl OwnerId {
+    #[inline]
+    pub fn to_def_id(self) -> DefId {
+        self.def_id.to_def_id()
+    }
+}
+
+impl rustc_index::Idx for OwnerId {
+    #[inline]
+    fn new(idx: usize) -> Self {
+        OwnerId { def_id: LocalDefId { local_def_index: DefIndex::from_usize(idx) } }
+    }
+
+    #[inline]
+    fn index(self) -> usize {
+        self.def_id.local_def_index.as_usize()
+    }
+}
+
+impl<CTX: HashStableContext> HashStable<CTX> for OwnerId {
+    #[inline]
+    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
+        self.to_stable_hash_key(hcx).hash_stable(hcx, hasher);
+    }
+}
+
+impl<CTX: HashStableContext> ToStableHashKey<CTX> for OwnerId {
+    type KeyType = DefPathHash;
+
+    #[inline]
+    fn to_stable_hash_key(&self, hcx: &CTX) -> DefPathHash {
+        hcx.def_path_hash(self.to_def_id())
+    }
+}
+
+/// Uniquely identifies a node in the HIR of the current crate. It is
+/// composed of the `owner`, which is the `LocalDefId` of the directly enclosing
+/// `hir::Item`, `hir::TraitItem`, or `hir::ImplItem` (i.e., the closest "item-like"),
+/// and the `local_id` which is unique within the given owner.
+///
+/// This two-level structure makes for more stable values: One can move an item
+/// around within the source code, or add or remove stuff before it, without
+/// the `local_id` part of the `HirId` changing, which is a very useful property in
+/// incremental compilation where we have to persist things through changes to
+/// the code base.
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Encodable, Decodable, HashStable_Generic)]
+#[rustc_pass_by_value]
+pub struct HirId {
+    pub owner: OwnerId,
+    pub local_id: ItemLocalId,
+}
+
+// To ensure correctness of incremental compilation,
+// `HirId` must not implement `Ord` or `PartialOrd`.
+// See https://github.com/rust-lang/rust/issues/90317.
+impl !Ord for HirId {}
+impl !PartialOrd for HirId {}
+
+impl Debug for HirId {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        // Example: HirId(DefId(0:1 ~ aa[7697]::{use#0}).10)
+        // Don't use debug_tuple to always keep this on one line.
+        write!(f, "HirId({:?}.{:?})", self.owner, self.local_id)
+    }
+}
+
+impl HirId {
+    /// Signal local id which should never be used.
+    pub const INVALID: HirId =
+        HirId { owner: OwnerId { def_id: CRATE_DEF_ID }, local_id: ItemLocalId::INVALID };
+
+    #[inline]
+    pub fn expect_owner(self) -> OwnerId {
+        assert_eq!(self.local_id.index(), 0);
+        self.owner
+    }
+
+    #[inline]
+    pub fn as_owner(self) -> Option<OwnerId> {
+        if self.local_id.index() == 0 { Some(self.owner) } else { None }
+    }
+
+    #[inline]
+    pub fn is_owner(self) -> bool {
+        self.local_id.index() == 0
+    }
+
+    #[inline]
+    pub fn make_owner(owner: LocalDefId) -> Self {
+        Self { owner: OwnerId { def_id: owner }, local_id: ItemLocalId::ZERO }
+    }
+}
+
+impl fmt::Display for HirId {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{self:?}")
+    }
+}
+
+rustc_data_structures::define_stable_id_collections!(HirIdMap, HirIdSet, HirIdMapEntry, HirId);
+rustc_data_structures::define_id_collections!(
+    ItemLocalMap,
+    ItemLocalSet,
+    ItemLocalMapEntry,
+    ItemLocalId
+);
+
+rustc_index::newtype_index! {
+    /// An `ItemLocalId` uniquely identifies something within a given "item-like";
+    /// that is, within a `hir::Item`, `hir::TraitItem`, or `hir::ImplItem`. There is no
+    /// guarantee that the numerical value of a given `ItemLocalId` corresponds to
+    /// the node's position within the owning item in any way, but there is a
+    /// guarantee that the `ItemLocalId`s within an owner occupy a dense range of
+    /// integers starting at zero, so a mapping that maps all or most nodes within
+    /// an "item-like" to something else can be implemented by a `Vec` instead of a
+    /// tree or hash map.
+    #[derive(HashStable_Generic)]
+    #[encodable]
+    #[orderable]
+    pub struct ItemLocalId {}
+}
+
+impl ItemLocalId {
+    /// Signal local id which should never be used.
+    pub const INVALID: ItemLocalId = ItemLocalId::MAX;
+}
+
+impl StableOrd for ItemLocalId {
+    const CAN_USE_UNSTABLE_SORT: bool = true;
+
+    // `Ord` is implemented as just comparing the ItemLocalId's numerical
+    // values and these are not changed by (de-)serialization.
+    const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED: () = ();
+}
+
+/// The `HirId` corresponding to `CRATE_NODE_ID` and `CRATE_DEF_ID`.
+pub const CRATE_HIR_ID: HirId =
+    HirId { owner: OwnerId { def_id: CRATE_DEF_ID }, local_id: ItemLocalId::ZERO };
+
+pub const CRATE_OWNER_ID: OwnerId = OwnerId { def_id: CRATE_DEF_ID };
+
+impl<CTX: rustc_span::HashStableContext> ToStableHashKey<CTX> for HirId {
+    type KeyType = (DefPathHash, ItemLocalId);
+
+    #[inline]
+    fn to_stable_hash_key(&self, hcx: &CTX) -> (DefPathHash, ItemLocalId) {
+        let def_path_hash = self.owner.def_id.to_stable_hash_key(hcx);
+        (def_path_hash, self.local_id)
+    }
+}
+
+impl<CTX: HashStableContext> ToStableHashKey<CTX> for ItemLocalId {
+    type KeyType = ItemLocalId;
+
+    #[inline]
+    fn to_stable_hash_key(&self, _: &CTX) -> ItemLocalId {
+        *self
+    }
+}