Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-def/src/hir.rs')
-rw-r--r--crates/hir-def/src/hir.rs86
1 files changed, 80 insertions, 6 deletions
diff --git a/crates/hir-def/src/hir.rs b/crates/hir-def/src/hir.rs
index a800569044..dcb2227d9f 100644
--- a/crates/hir-def/src/hir.rs
+++ b/crates/hir-def/src/hir.rs
@@ -16,11 +16,11 @@ pub mod format_args;
pub mod generics;
pub mod type_ref;
-use std::fmt;
+use std::{fmt, mem};
use hir_expand::{MacroDefId, name::Name};
use intern::Symbol;
-use la_arena::Idx;
+use la_arena::{Idx, RawIdx};
use rustc_apfloat::ieee::{Double, Half, Quad, Single};
use syntax::ast;
use type_ref::TypeRefId;
@@ -43,9 +43,7 @@ pub type ExprId = Idx<Expr>;
pub type PatId = Idx<Pat>;
-// FIXME: Encode this as a single u32, we won't ever reach all 32 bits especially given these counts
-// are local to the body.
-#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, salsa::Update)]
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub enum ExprOrPatId {
ExprId(ExprId),
PatId(PatId),
@@ -74,7 +72,83 @@ impl ExprOrPatId {
matches!(self, Self::PatId(_))
}
}
-stdx::impl_from!(ExprId, PatId for ExprOrPatId);
+
+#[derive(Copy, Clone, Hash, PartialEq, Eq, salsa::Update)]
+pub struct ExprOrPatIdPacked(u32);
+
+const _: () = assert!(mem::size_of::<ExprOrPatIdPacked>() == mem::size_of::<u32>());
+
+impl ExprOrPatIdPacked {
+ const PAT_BIT: u32 = 1 << (u32::BITS - 1);
+ const INDEX_MASK: u32 = !Self::PAT_BIT;
+
+ pub fn unpack(self) -> ExprOrPatId {
+ match self.is_expr() {
+ true => ExprOrPatId::ExprId(ExprId::from_raw(RawIdx::from_u32(self.0))),
+ false => {
+ ExprOrPatId::PatId(PatId::from_raw(RawIdx::from_u32(self.0 & Self::INDEX_MASK)))
+ }
+ }
+ }
+
+ #[inline]
+ pub fn as_expr(self) -> Option<ExprId> {
+ self.is_expr().then(|| ExprId::from_raw(RawIdx::from_u32(self.0)))
+ }
+
+ #[inline]
+ pub fn is_expr(&self) -> bool {
+ self.0 & Self::PAT_BIT == 0
+ }
+
+ #[inline]
+ pub fn as_pat(self) -> Option<PatId> {
+ self.is_pat().then(|| PatId::from_raw(RawIdx::from_u32(self.0 & Self::INDEX_MASK)))
+ }
+
+ #[inline]
+ pub fn is_pat(&self) -> bool {
+ self.0 & Self::PAT_BIT != 0
+ }
+}
+
+impl fmt::Debug for ExprOrPatIdPacked {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self.unpack() {
+ ExprOrPatId::ExprId(id) => f.debug_tuple("ExprId").field(&id).finish(),
+ ExprOrPatId::PatId(id) => f.debug_tuple("PatId").field(&id).finish(),
+ }
+ }
+}
+
+impl From<ExprId> for ExprOrPatIdPacked {
+ fn from(value: ExprId) -> Self {
+ let value = value.into_raw().into_u32();
+ // virtually impossible to have IDs that high
+ debug_assert_eq!(value & Self::PAT_BIT, 0);
+ Self(value)
+ }
+}
+
+impl From<PatId> for ExprOrPatId {
+ fn from(value: PatId) -> Self {
+ ExprOrPatId::PatId(value)
+ }
+}
+impl From<ExprId> for ExprOrPatId {
+ fn from(value: ExprId) -> Self {
+ ExprOrPatId::ExprId(value)
+ }
+}
+
+impl From<PatId> for ExprOrPatIdPacked {
+ fn from(value: PatId) -> Self {
+ let value = value.into_raw().into_u32();
+ // virtually impossible to have IDs that high
+ debug_assert_eq!(value & Self::PAT_BIT, 0);
+ Self(value | Self::PAT_BIT)
+ }
+}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Label {