Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/consteval.rs')
| -rw-r--r-- | crates/hir-ty/src/consteval.rs | 251 |
1 files changed, 108 insertions, 143 deletions
diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs index 928396c63a..80e7e05d76 100644 --- a/crates/hir-ty/src/consteval.rs +++ b/crates/hir-ty/src/consteval.rs @@ -8,28 +8,30 @@ use hir_def::{ ConstId, EnumVariantId, ExpressionStoreOwnerId, GeneralConstId, GenericDefId, HasModule, StaticId, attrs::AttrFlags, - builtin_type::{BuiltinInt, BuiltinType, BuiltinUint}, expr_store::{Body, ExpressionStore}, hir::{Expr, ExprId, Literal}, }; use hir_expand::Lookup; +use rustc_abi::Size; +use rustc_apfloat::Float; use rustc_type_ir::inherent::IntoKind; +use stdx::never; use triomphe::Arc; use crate::{ - LifetimeElisionKind, MemoryMap, ParamEnvAndCrate, TyLoweringContext, + LifetimeElisionKind, ParamEnvAndCrate, TyLoweringContext, db::HirDatabase, display::DisplayTarget, infer::InferenceContext, - mir::{MirEvalError, MirLowerError}, + mir::{MirEvalError, MirLowerError, pad16}, next_solver::{ - Const, ConstBytes, ConstKind, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, - StoredConst, StoredGenericArgs, Ty, ValueConst, + Allocation, Const, ConstKind, Consts, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, + ScalarInt, StoredAllocation, StoredGenericArgs, Ty, TyKind, ValTreeKind, default_types, }, traits::StoredParamEnvAndCrate, }; -use super::mir::{interpret_mir, lower_body_to_mir, pad16}; +use super::mir::{interpret_mir, lower_body_to_mir}; pub fn unknown_const<'db>(_ty: Ty<'db>) -> Const<'db> { Const::new(DbInterner::conjure(), rustc_type_ir::ConstKind::Error(ErrorGuaranteed)) @@ -84,140 +86,87 @@ pub fn intern_const_ref<'a>( db: &'a dyn HirDatabase, value: &Literal, ty: Ty<'a>, - _krate: Crate, + krate: Crate, ) -> Const<'a> { let interner = DbInterner::new_no_crate(db); - let kind = match value { - &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, memory_map: MemoryMap::default() }, - )) + let Ok(data_layout) = db.target_data_layout(krate) else { + return Const::error(interner); + }; + let valtree = match (ty.kind(), value) { + (TyKind::Uint(uint), Literal::Uint(value, _)) => { + let size = uint.bit_width().map(Size::from_bits).unwrap_or(data_layout.pointer_size()); + let scalar = ScalarInt::try_from_uint(*value, size).unwrap(); + ValTreeKind::Leaf(scalar) } - &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, memory_map: MemoryMap::default() }, - )) + (TyKind::Uint(uint), Literal::Int(value, _)) => { + // `Literal::Int` is the default, so we also need to account for the type being uint. + let size = uint.bit_width().map(Size::from_bits).unwrap_or(data_layout.pointer_size()); + let scalar = ScalarInt::try_from_uint(*value as u128, size).unwrap(); + ValTreeKind::Leaf(scalar) } - &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() }, - )) + (TyKind::Int(int), Literal::Int(value, _)) => { + let size = int.bit_width().map(Size::from_bits).unwrap_or(data_layout.pointer_size()); + let scalar = ScalarInt::try_from_int(*value, size).unwrap(); + ValTreeKind::Leaf(scalar) } - 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!(), + (TyKind::Bool, Literal::Bool(value)) => ValTreeKind::Leaf(ScalarInt::from(*value)), + (TyKind::Char, Literal::Char(value)) => ValTreeKind::Leaf(ScalarInt::from(*value)), + (TyKind::Float(float), Literal::Float(value, _)) => { + let size = Size::from_bits(float.bit_width()); + let value = match float { + rustc_ast_ir::FloatTy::F16 => value.to_f16().to_bits(), + rustc_ast_ir::FloatTy::F32 => value.to_f32().to_bits(), + rustc_ast_ir::FloatTy::F64 => value.to_f64().to_bits(), + rustc_ast_ir::FloatTy::F128 => value.to_f128().to_bits(), }; - rustc_type_ir::ConstKind::Value(ValueConst::new( - ty, - ConstBytes { memory, memory_map: MemoryMap::default() }, + let scalar = ScalarInt::try_from_uint(value, size).unwrap(); + ValTreeKind::Leaf(scalar) + } + (_, Literal::String(value)) => { + let u8_values = &interner.default_types().consts.u8_values; + ValTreeKind::Branch(Consts::new_from_iter( + interner, + value.as_str().as_bytes().iter().map(|&byte| u8_values[usize::from(byte)]), )) } - 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() }, - )), - 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(), - }, - )), - 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() }, + (_, Literal::ByteString(value)) => { + let u8_values = &interner.default_types().consts.u8_values; + ValTreeKind::Branch(Consts::new_from_iter( + interner, + value.iter().map(|&byte| u8_values[usize::from(byte)]), )) } - // FIXME - Literal::CString(_items) => rustc_type_ir::ConstKind::Error(ErrorGuaranteed), - _ => rustc_type_ir::ConstKind::Error(ErrorGuaranteed), + (_, Literal::CString(_)) => { + // FIXME: + return Const::error(interner); + } + _ => { + never!("mismatching type for literal"); + return Const::error(interner); + } }; - Const::new(interner, kind) + Const::new_valtree(interner, ty, valtree) } /// Interns a possibly-unknown target usize pub fn usize_const<'db>(db: &'db dyn HirDatabase, value: Option<u128>, krate: Crate) -> Const<'db> { - intern_const_ref( - db, - &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, - ) + let interner = DbInterner::new_no_crate(db); + let value = match value { + Some(value) => value, + None => { + return Const::error(interner); + } + }; + let Ok(data_layout) = db.target_data_layout(krate) else { + return Const::error(interner); + }; + let usize_ty = interner.default_types().types.usize; + let scalar = ScalarInt::try_from_uint(value, data_layout.pointer_size()).unwrap(); + Const::new_valtree(interner, usize_ty, ValTreeKind::Leaf(scalar)) +} + +pub fn allocation_as_usize(ec: Allocation<'_>) -> u128 { + u128::from_le_bytes(pad16(&ec.memory, false)) } pub fn try_const_usize<'db>(db: &'db dyn HirDatabase, c: Const<'db>) -> Option<u128> { @@ -230,20 +179,30 @@ pub fn try_const_usize<'db>(db: &'db dyn HirDatabase, c: Const<'db>) -> Option<u GeneralConstId::ConstId(id) => { let subst = unevaluated_const.args; let ec = db.const_eval(id, subst, None).ok()?; - try_const_usize(db, ec) + Some(allocation_as_usize(ec)) } GeneralConstId::StaticId(id) => { let ec = db.const_eval_static(id).ok()?; - try_const_usize(db, ec) + Some(allocation_as_usize(ec)) } GeneralConstId::AnonConstId(_) => None, }, - ConstKind::Value(val) => Some(u128::from_le_bytes(pad16(&val.value.inner().memory, false))), + ConstKind::Value(val) => { + if val.ty == default_types(db).types.usize { + Some(val.value.inner().to_leaf().to_uint_unchecked()) + } else { + None + } + } ConstKind::Error(_) => None, ConstKind::Expr(_) => None, } } +pub fn allocation_as_isize(ec: Allocation<'_>) -> i128 { + i128::from_le_bytes(pad16(&ec.memory, true)) +} + pub fn try_const_isize<'db>(db: &'db dyn HirDatabase, c: &Const<'db>) -> Option<i128> { match (*c).kind() { ConstKind::Param(_) => None, @@ -254,15 +213,21 @@ pub fn try_const_isize<'db>(db: &'db dyn HirDatabase, c: &Const<'db>) -> Option< GeneralConstId::ConstId(id) => { let subst = unevaluated_const.args; let ec = db.const_eval(id, subst, None).ok()?; - try_const_isize(db, &ec) + Some(allocation_as_isize(ec)) } GeneralConstId::StaticId(id) => { let ec = db.const_eval_static(id).ok()?; - try_const_isize(db, &ec) + Some(allocation_as_isize(ec)) } GeneralConstId::AnonConstId(_) => None, }, - ConstKind::Value(val) => Some(i128::from_le_bytes(pad16(&val.value.inner().memory, true))), + ConstKind::Value(val) => { + if val.ty == default_types(db).types.isize { + Some(val.value.inner().to_leaf().to_int_unchecked()) + } else { + None + } + } ConstKind::Error(_) => None, ConstKind::Expr(_) => None, } @@ -299,11 +264,7 @@ pub(crate) fn const_eval_discriminant_variant( .store(), )?; let c = interpret_mir(db, mir_body, false, None)?.0?; - let c = if is_signed { - try_const_isize(db, &c).unwrap() - } else { - try_const_usize(db, c).unwrap() as i128 - }; + let c = if is_signed { allocation_as_isize(c) } else { allocation_as_usize(c) as i128 }; Ok(c) } @@ -341,7 +302,11 @@ pub(crate) fn eval_to_const<'db>(expr: ExprId, ctx: &mut InferenceContext<'_, 'd lower_body_to_mir(ctx.db, body_owner, Body::of(ctx.db, body_owner), &infer, expr) && let Ok((Ok(result), _)) = interpret_mir(ctx.db, Arc::new(mir_body), true, None) { - return result; + return Const::new_from_allocation( + ctx.interner(), + &result, + ParamEnvAndCrate { param_env: ctx.table.param_env, krate: ctx.resolver.krate() }, + ); } Const::error(ctx.interner()) } @@ -359,7 +324,7 @@ pub(crate) fn const_eval<'db>( def: ConstId, subst: GenericArgs<'db>, trait_env: Option<ParamEnvAndCrate<'db>>, -) -> Result<Const<'db>, ConstEvalError> { +) -> Result<Allocation<'db>, ConstEvalError> { return match const_eval_query(db, def, subst.store(), trait_env.map(|env| env.store())) { Ok(konst) => Ok(konst.as_ref()), Err(err) => Err(err.clone()), @@ -371,7 +336,7 @@ pub(crate) fn const_eval<'db>( def: ConstId, subst: StoredGenericArgs, trait_env: Option<StoredParamEnvAndCrate>, - ) -> Result<StoredConst, ConstEvalError> { + ) -> Result<StoredAllocation, ConstEvalError> { let body = db.monomorphized_mir_body( def.into(), subst, @@ -392,7 +357,7 @@ pub(crate) fn const_eval<'db>( _: ConstId, _: StoredGenericArgs, _: Option<StoredParamEnvAndCrate>, - ) -> Result<StoredConst, ConstEvalError> { + ) -> Result<StoredAllocation, ConstEvalError> { Err(ConstEvalError::MirLowerError(MirLowerError::Loop)) } } @@ -400,7 +365,7 @@ pub(crate) fn const_eval<'db>( pub(crate) fn const_eval_static<'db>( db: &'db dyn HirDatabase, def: StaticId, -) -> Result<Const<'db>, ConstEvalError> { +) -> Result<Allocation<'db>, ConstEvalError> { return match const_eval_static_query(db, def) { Ok(konst) => Ok(konst.as_ref()), Err(err) => Err(err.clone()), @@ -410,7 +375,7 @@ pub(crate) fn const_eval_static<'db>( pub(crate) fn const_eval_static_query<'db>( db: &'db dyn HirDatabase, def: StaticId, - ) -> Result<StoredConst, ConstEvalError> { + ) -> Result<StoredAllocation, ConstEvalError> { let interner = DbInterner::new_no_crate(db); let body = db.monomorphized_mir_body( def.into(), @@ -430,7 +395,7 @@ pub(crate) fn const_eval_static<'db>( _: &dyn HirDatabase, _: salsa::Id, _: StaticId, - ) -> Result<StoredConst, ConstEvalError> { + ) -> Result<StoredAllocation, ConstEvalError> { Err(ConstEvalError::MirLowerError(MirLowerError::Loop)) } } |