From 8ecf6fcda6eb8d4464367fe0c99bf082cc9ad8e1 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 2 Jan 2026 11:04:27 +0100 Subject: [PATCH] Remove unnecessary `ConstLiteralRef` enum --- crates/hir-def/src/expr_store/lower.rs | 1 - crates/hir-def/src/hir/type_ref.rs | 58 +---------- crates/hir-ty/src/consteval.rs | 131 ++++++++++++++++++++----- crates/hir-ty/src/lower.rs | 24 ++--- crates/hir-ty/src/next_solver/ty.rs | 18 ++++ 5 files changed, 132 insertions(+), 100 deletions(-) diff --git a/crates/hir-def/src/expr_store/lower.rs b/crates/hir-def/src/expr_store/lower.rs index af274f1a48..d3774ded39 100644 --- a/crates/hir-def/src/expr_store/lower.rs +++ b/crates/hir-def/src/expr_store/lower.rs @@ -2319,7 +2319,6 @@ impl<'db> ExprCollector<'db> { ast::Pat::SlicePat(p) => { let SlicePatComponents { prefix, slice, suffix } = p.components(); - // FIXME properly handle `RestPat` Pat::Slice { prefix: prefix.into_iter().map(|p| self.collect_pat(p, binding_list)).collect(), slice: slice.map(|p| self.collect_pat(p, binding_list)), diff --git a/crates/hir-def/src/hir/type_ref.rs b/crates/hir-def/src/hir/type_ref.rs index ad8535413d..b64199fa26 100644 --- a/crates/hir-def/src/hir/type_ref.rs +++ b/crates/hir-def/src/hir/type_ref.rs @@ -1,8 +1,6 @@ //! HIR for references to types. Paths in these are not yet resolved. They can //! be directly created from an ast::TypeRef, without further queries. -use std::fmt::Write; - use hir_expand::name::Name; use intern::Symbol; use la_arena::Idx; @@ -10,12 +8,11 @@ use thin_vec::ThinVec; use crate::{ LifetimeParamId, TypeParamId, - builtin_type::{BuiltinInt, BuiltinType, BuiltinUint}, expr_store::{ ExpressionStore, path::{GenericArg, Path}, }, - hir::{ExprId, Literal}, + hir::ExprId, }; #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] @@ -275,56 +272,3 @@ impl TypeBound { pub struct ConstRef { pub expr: ExprId, } - -/// A literal constant value -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum LiteralConstRef { - Int(i128), - UInt(u128), - Bool(bool), - Char(char), - - /// Case of an unknown value that rustc might know but we don't - // FIXME: this is a hack to get around chalk not being able to represent unevaluatable - // constants - // https://github.com/rust-lang/rust-analyzer/pull/8813#issuecomment-840679177 - // https://rust-lang.zulipchat.com/#narrow/stream/144729-wg-traits/topic/Handling.20non.20evaluatable.20constants'.20equality/near/238386348 - Unknown, -} - -impl LiteralConstRef { - pub fn builtin_type(&self) -> BuiltinType { - match self { - LiteralConstRef::UInt(_) | LiteralConstRef::Unknown => { - BuiltinType::Uint(BuiltinUint::U128) - } - LiteralConstRef::Int(_) => BuiltinType::Int(BuiltinInt::I128), - LiteralConstRef::Char(_) => BuiltinType::Char, - LiteralConstRef::Bool(_) => BuiltinType::Bool, - } - } -} - -impl From for LiteralConstRef { - fn from(literal: Literal) -> Self { - match literal { - Literal::Char(c) => Self::Char(c), - Literal::Bool(flag) => Self::Bool(flag), - Literal::Int(num, _) => Self::Int(num), - Literal::Uint(num, _) => Self::UInt(num), - _ => Self::Unknown, - } - } -} - -impl std::fmt::Display for LiteralConstRef { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { - match self { - LiteralConstRef::Int(num) => num.fmt(f), - LiteralConstRef::UInt(num) => num.fmt(f), - LiteralConstRef::Bool(flag) => flag.fmt(f), - LiteralConstRef::Char(c) => write!(f, "'{c}'"), - LiteralConstRef::Unknown => f.write_char('_'), - } - } -} diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs index f11240e0f7..5bc2446fdd 100644 --- a/crates/hir-ty/src/consteval.rs +++ b/crates/hir-ty/src/consteval.rs @@ -7,9 +7,9 @@ use base_db::Crate; use hir_def::{ ConstId, EnumVariantId, GeneralConstId, HasModule, StaticId, attrs::AttrFlags, + builtin_type::{BuiltinInt, BuiltinType, BuiltinUint}, expr_store::Body, - hir::{Expr, ExprId}, - type_ref::LiteralConstRef, + hir::{Expr, ExprId, Literal}, }; use hir_expand::Lookup; use rustc_type_ir::inherent::IntoKind; @@ -23,7 +23,7 @@ use crate::{ mir::{MirEvalError, MirLowerError}, next_solver::{ Const, ConstBytes, ConstKind, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, - ParamEnv, StoredConst, StoredGenericArgs, Ty, ValueConst, + StoredConst, StoredGenericArgs, Ty, ValueConst, }, traits::StoredParamEnvAndCrate, }; @@ -81,47 +81,122 @@ impl From for ConstEvalError { /// Interns a constant scalar with the given type pub fn intern_const_ref<'a>( db: &'a dyn HirDatabase, - value: &LiteralConstRef, + value: &Literal, ty: Ty<'a>, - krate: Crate, + _krate: Crate, ) -> Const<'a> { let interner = DbInterner::new_no_crate(db); - let layout = db - .layout_of_ty(ty.store(), ParamEnvAndCrate { param_env: ParamEnv::empty(), krate }.store()); let kind = match value { - LiteralConstRef::Int(i) => { - // FIXME: We should handle failure of layout better. - let size = layout.map(|it| it.size.bytes_usize()).unwrap_or(16); + &Literal::Uint(i, builtin_ty) + if builtin_ty.is_none() || ty.as_builtin() == builtin_ty.map(BuiltinType::Uint) => + { + let memory = match ty.as_builtin() { + Some(BuiltinType::Uint(builtin_uint)) => match builtin_uint { + BuiltinUint::U8 => Box::new([i as u8]) as Box<[u8]>, + BuiltinUint::U16 => Box::new((i as u16).to_le_bytes()), + BuiltinUint::U32 => Box::new((i as u32).to_le_bytes()), + BuiltinUint::U64 => Box::new((i as u64).to_le_bytes()), + BuiltinUint::U128 => Box::new((i).to_le_bytes()), + BuiltinUint::Usize => Box::new((i as usize).to_le_bytes()), + }, + _ => return Const::new(interner, rustc_type_ir::ConstKind::Error(ErrorGuaranteed)), + }; rustc_type_ir::ConstKind::Value(ValueConst::new( ty, - ConstBytes { - memory: i.to_le_bytes()[0..size].into(), - memory_map: MemoryMap::default(), - }, + ConstBytes { memory, memory_map: MemoryMap::default() }, )) } - LiteralConstRef::UInt(i) => { - let size = layout.map(|it| it.size.bytes_usize()).unwrap_or(16); + &Literal::Int(i, None) + if ty + .as_builtin() + .is_some_and(|builtin_ty| matches!(builtin_ty, BuiltinType::Uint(_))) => + { + let memory = match ty.as_builtin() { + Some(BuiltinType::Uint(builtin_uint)) => match builtin_uint { + BuiltinUint::U8 => Box::new([i as u8]) as Box<[u8]>, + BuiltinUint::U16 => Box::new((i as u16).to_le_bytes()), + BuiltinUint::U32 => Box::new((i as u32).to_le_bytes()), + BuiltinUint::U64 => Box::new((i as u64).to_le_bytes()), + BuiltinUint::U128 => Box::new((i as u128).to_le_bytes()), + BuiltinUint::Usize => Box::new((i as usize).to_le_bytes()), + }, + _ => return Const::new(interner, rustc_type_ir::ConstKind::Error(ErrorGuaranteed)), + }; rustc_type_ir::ConstKind::Value(ValueConst::new( ty, - ConstBytes { - memory: i.to_le_bytes()[0..size].into(), - memory_map: MemoryMap::default(), - }, + ConstBytes { memory, memory_map: MemoryMap::default() }, )) } - LiteralConstRef::Bool(b) => rustc_type_ir::ConstKind::Value(ValueConst::new( + &Literal::Int(i, builtin_ty) + if builtin_ty.is_none() || ty.as_builtin() == builtin_ty.map(BuiltinType::Int) => + { + let memory = match ty.as_builtin() { + Some(BuiltinType::Int(builtin_int)) => match builtin_int { + BuiltinInt::I8 => Box::new([i as u8]) as Box<[u8]>, + BuiltinInt::I16 => Box::new((i as i16).to_le_bytes()), + BuiltinInt::I32 => Box::new((i as i32).to_le_bytes()), + BuiltinInt::I64 => Box::new((i as i64).to_le_bytes()), + BuiltinInt::I128 => Box::new((i).to_le_bytes()), + BuiltinInt::Isize => Box::new((i as isize).to_le_bytes()), + }, + _ => return Const::new(interner, rustc_type_ir::ConstKind::Error(ErrorGuaranteed)), + }; + rustc_type_ir::ConstKind::Value(ValueConst::new( + ty, + ConstBytes { memory, memory_map: MemoryMap::default() }, + )) + } + Literal::Float(float_type_wrapper, builtin_float) + if builtin_float.is_none() + || ty.as_builtin() == builtin_float.map(BuiltinType::Float) => + { + let memory = match ty.as_builtin().unwrap() { + BuiltinType::Float(builtin_float) => match builtin_float { + // FIXME: + hir_def::builtin_type::BuiltinFloat::F16 => Box::new([0u8; 2]) as Box<[u8]>, + hir_def::builtin_type::BuiltinFloat::F32 => { + Box::new(float_type_wrapper.to_f32().to_le_bytes()) + } + hir_def::builtin_type::BuiltinFloat::F64 => { + Box::new(float_type_wrapper.to_f64().to_le_bytes()) + } + // FIXME: + hir_def::builtin_type::BuiltinFloat::F128 => Box::new([0; 16]), + }, + _ => unreachable!(), + }; + rustc_type_ir::ConstKind::Value(ValueConst::new( + ty, + ConstBytes { memory, memory_map: MemoryMap::default() }, + )) + } + Literal::Bool(b) if ty.is_bool() => rustc_type_ir::ConstKind::Value(ValueConst::new( ty, ConstBytes { memory: Box::new([*b as u8]), memory_map: MemoryMap::default() }, )), - LiteralConstRef::Char(c) => rustc_type_ir::ConstKind::Value(ValueConst::new( + Literal::Char(c) if ty.is_char() => rustc_type_ir::ConstKind::Value(ValueConst::new( ty, ConstBytes { memory: (*c as u32).to_le_bytes().into(), memory_map: MemoryMap::default(), }, )), - LiteralConstRef::Unknown => rustc_type_ir::ConstKind::Error(ErrorGuaranteed), + Literal::String(symbol) if ty.is_str() => rustc_type_ir::ConstKind::Value(ValueConst::new( + ty, + ConstBytes { + memory: symbol.as_str().as_bytes().into(), + memory_map: MemoryMap::default(), + }, + )), + Literal::ByteString(items) if ty.as_slice().is_some_and(|ty| ty.is_u8()) => { + rustc_type_ir::ConstKind::Value(ValueConst::new( + ty, + ConstBytes { memory: items.clone(), memory_map: MemoryMap::default() }, + )) + } + // FIXME + Literal::CString(_items) => rustc_type_ir::ConstKind::Error(ErrorGuaranteed), + _ => rustc_type_ir::ConstKind::Error(ErrorGuaranteed), }; Const::new(interner, kind) } @@ -130,7 +205,15 @@ pub fn intern_const_ref<'a>( pub fn usize_const<'db>(db: &'db dyn HirDatabase, value: Option, krate: Crate) -> Const<'db> { intern_const_ref( db, - &value.map_or(LiteralConstRef::Unknown, LiteralConstRef::UInt), + &match value { + Some(value) => Literal::Uint(value, Some(BuiltinUint::Usize)), + None => { + return Const::new( + DbInterner::new_no_crate(db), + rustc_type_ir::ConstKind::Error(ErrorGuaranteed), + ); + } + }, Ty::new_uint(DbInterner::new_no_crate(db), rustc_type_ir::UintTy::Usize), krate, ) diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index 9307868f39..6688cf3d60 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -27,8 +27,8 @@ use hir_def::{ resolver::{HasResolver, LifetimeNs, Resolver, TypeNs, ValueNs}, signatures::{FunctionSignature, TraitFlags, TypeAliasFlags}, type_ref::{ - ConstRef, LifetimeRefId, LiteralConstRef, PathId, TraitBoundModifier, - TraitRef as HirTraitRef, TypeBound, TypeRef, TypeRefId, + ConstRef, LifetimeRefId, PathId, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, + TypeRef, TypeRefId, }, }; use hir_expand::name::Name; @@ -281,21 +281,9 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { hir_def::hir::Expr::Path(path) => { self.path_to_const(path).unwrap_or_else(|| unknown_const(const_type)) } - hir_def::hir::Expr::Literal(literal) => intern_const_ref( - self.db, - &match *literal { - hir_def::hir::Literal::Float(_, _) - | hir_def::hir::Literal::String(_) - | hir_def::hir::Literal::ByteString(_) - | hir_def::hir::Literal::CString(_) => LiteralConstRef::Unknown, - hir_def::hir::Literal::Char(c) => LiteralConstRef::Char(c), - hir_def::hir::Literal::Bool(b) => LiteralConstRef::Bool(b), - hir_def::hir::Literal::Int(val, _) => LiteralConstRef::Int(val), - hir_def::hir::Literal::Uint(val, _) => LiteralConstRef::UInt(val), - }, - const_type, - self.resolver.krate(), - ), + hir_def::hir::Expr::Literal(literal) => { + intern_const_ref(self.db, literal, const_type, self.resolver.krate()) + } hir_def::hir::Expr::UnaryOp { expr: inner_expr, op: hir_def::hir::UnaryOp::Neg } => { if let hir_def::hir::Expr::Literal(literal) = &self.store[*inner_expr] { // Only handle negation for signed integers and floats @@ -304,7 +292,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { if let Some(negated_literal) = literal.clone().negate() { intern_const_ref( self.db, - &negated_literal.into(), + &negated_literal, const_type, self.resolver.krate(), ) diff --git a/crates/hir-ty/src/next_solver/ty.rs b/crates/hir-ty/src/next_solver/ty.rs index 030ba37015..66a24d3949 100644 --- a/crates/hir-ty/src/next_solver/ty.rs +++ b/crates/hir-ty/src/next_solver/ty.rs @@ -383,6 +383,11 @@ impl<'db> Ty<'db> { matches!(self.kind(), TyKind::Bool) } + #[inline] + pub fn is_char(self) -> bool { + matches!(self.kind(), TyKind::Char) + } + /// A scalar type is one that denotes an atomic datum, with no sub-components. /// (A RawPtr is scalar because it represents a non-managed pointer, so its /// contents are abstract to rustc.) @@ -422,6 +427,11 @@ impl<'db> Ty<'db> { matches!(self.kind(), TyKind::Tuple(tys) if tys.is_empty()) } + #[inline] + pub fn is_u8(self) -> bool { + matches!(self.kind(), TyKind::Uint(UintTy::U8)) + } + #[inline] pub fn is_raw_ptr(self) -> bool { matches!(self.kind(), TyKind::RawPtr(..)) @@ -456,6 +466,14 @@ impl<'db> Ty<'db> { } } + #[inline] + pub fn as_slice(self) -> Option> { + match self.kind() { + TyKind::Slice(ty) => Some(ty), + _ => None, + } + } + #[inline] pub fn ty_vid(self) -> Option { match self.kind() {