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.rs | 86 |
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 { |