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 | 97 |
1 files changed, 75 insertions, 22 deletions
diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs index 5830c48988..40b63b17b5 100644 --- a/crates/hir-ty/src/consteval.rs +++ b/crates/hir-ty/src/consteval.rs @@ -3,19 +3,20 @@ use base_db::CrateId; use chalk_ir::{BoundVar, DebruijnIndex, GenericArgData}; use hir_def::{ - expr::Expr, - path::ModPath, + hir::Expr, + path::Path, resolver::{Resolver, ValueNs}, type_ref::ConstRef, - ConstId, EnumVariantId, + EnumVariantId, GeneralConstId, StaticId, }; use la_arena::{Idx, RawIdx}; use stdx::never; +use triomphe::Arc; use crate::{ - db::HirDatabase, infer::InferenceContext, layout::layout_of_ty, lower::ParamLoweringMode, - to_placeholder_idx, utils::Generics, Const, ConstData, ConstScalar, ConstValue, GenericArg, - Interner, MemoryMap, Ty, TyBuilder, + db::HirDatabase, infer::InferenceContext, lower::ParamLoweringMode, + mir::monomorphize_mir_body_bad, to_placeholder_idx, utils::Generics, Const, ConstData, + ConstScalar, ConstValue, GenericArg, Interner, MemoryMap, Substitution, Ty, TyBuilder, }; use super::mir::{interpret_mir, lower_to_mir, pad16, MirEvalError, MirLowerError}; @@ -57,7 +58,7 @@ pub enum ConstEvalError { impl From<MirLowerError> for ConstEvalError { fn from(value: MirLowerError) -> Self { match value { - MirLowerError::ConstEvalError(e) => *e, + MirLowerError::ConstEvalError(_, e) => *e, _ => ConstEvalError::MirLowerError(value), } } @@ -72,10 +73,11 @@ impl From<MirEvalError> for ConstEvalError { pub(crate) fn path_to_const( db: &dyn HirDatabase, resolver: &Resolver, - path: &ModPath, + path: &Path, mode: ParamLoweringMode, args_lazy: impl FnOnce() -> Generics, debruijn: DebruijnIndex, + expected_ty: Ty, ) -> Option<Const> { match resolver.resolve_path_in_value_ns_fully(db.upcast(), path) { Some(ValueNs::GenericParam(p)) => { @@ -89,7 +91,7 @@ pub(crate) fn path_to_const( Some(x) => ConstValue::BoundVar(BoundVar::new(debruijn, x)), None => { never!( - "Generic list doesn't contain this param: {:?}, {}, {:?}", + "Generic list doesn't contain this param: {:?}, {:?}, {:?}", args, path, p @@ -100,6 +102,10 @@ pub(crate) fn path_to_const( }; Some(ConstData { ty, value }.intern(Interner)) } + Some(ValueNs::ConstId(c)) => Some(intern_const_scalar( + ConstScalar::UnevaluatedConst(c.into(), Substitution::empty(Interner)), + expected_ty, + )), _ => None, } } @@ -124,14 +130,15 @@ pub fn intern_const_scalar(value: ConstScalar, ty: Ty) -> Const { /// Interns a constant scalar with the given type pub fn intern_const_ref(db: &dyn HirDatabase, value: &ConstRef, ty: Ty, krate: CrateId) -> Const { + let layout = db.layout_of_ty(ty.clone(), krate); let bytes = match value { ConstRef::Int(i) => { // FIXME: We should handle failure of layout better. - let size = layout_of_ty(db, &ty, krate).map(|x| x.size.bytes_usize()).unwrap_or(16); + let size = layout.map(|x| x.size.bytes_usize()).unwrap_or(16); ConstScalar::Bytes(i.to_le_bytes()[0..size].to_vec(), MemoryMap::default()) } ConstRef::UInt(i) => { - let size = layout_of_ty(db, &ty, krate).map(|x| x.size.bytes_usize()).unwrap_or(16); + let size = layout.map(|x| x.size.bytes_usize()).unwrap_or(16); ConstScalar::Bytes(i.to_le_bytes()[0..size].to_vec(), MemoryMap::default()) } ConstRef::Bool(b) => ConstScalar::Bytes(vec![*b as u8], MemoryMap::default()), @@ -153,13 +160,17 @@ pub fn usize_const(db: &dyn HirDatabase, value: Option<u128>, krate: CrateId) -> ) } -pub fn try_const_usize(c: &Const) -> Option<u128> { +pub fn try_const_usize(db: &dyn HirDatabase, c: &Const) -> Option<u128> { match &c.data(Interner).value { chalk_ir::ConstValue::BoundVar(_) => None, chalk_ir::ConstValue::InferenceVar(_) => None, chalk_ir::ConstValue::Placeholder(_) => None, chalk_ir::ConstValue::Concrete(c) => match &c.interned { ConstScalar::Bytes(x, _) => Some(u128::from_le_bytes(pad16(&x, false))), + ConstScalar::UnevaluatedConst(c, subst) => { + let ec = db.const_eval(*c, subst.clone()).ok()?; + try_const_usize(db, &ec) + } _ => None, }, } @@ -168,7 +179,16 @@ pub fn try_const_usize(c: &Const) -> Option<u128> { pub(crate) fn const_eval_recover( _: &dyn HirDatabase, _: &[String], - _: &ConstId, + _: &GeneralConstId, + _: &Substitution, +) -> Result<Const, ConstEvalError> { + Err(ConstEvalError::MirLowerError(MirLowerError::Loop)) +} + +pub(crate) fn const_eval_static_recover( + _: &dyn HirDatabase, + _: &[String], + _: &StaticId, ) -> Result<Const, ConstEvalError> { Err(ConstEvalError::MirLowerError(MirLowerError::Loop)) } @@ -183,11 +203,39 @@ pub(crate) fn const_eval_discriminant_recover( pub(crate) fn const_eval_query( db: &dyn HirDatabase, - const_id: ConstId, + def: GeneralConstId, + subst: Substitution, +) -> Result<Const, ConstEvalError> { + let body = match def { + GeneralConstId::ConstId(c) => { + db.monomorphized_mir_body(c.into(), subst, db.trait_environment(c.into()))? + } + GeneralConstId::AnonymousConstId(c) => { + let (def, root) = db.lookup_intern_anonymous_const(c); + let body = db.body(def); + let infer = db.infer(def); + Arc::new(monomorphize_mir_body_bad( + db, + lower_to_mir(db, def, &body, &infer, root)?, + subst, + db.trait_environment_for_body(def), + )?) + } + }; + let c = interpret_mir(db, &body, false).0?; + Ok(c) +} + +pub(crate) fn const_eval_static_query( + db: &dyn HirDatabase, + def: StaticId, ) -> Result<Const, ConstEvalError> { - let def = const_id.into(); - let body = db.mir_body(def)?; - let c = interpret_mir(db, &body, false)?; + let body = db.monomorphized_mir_body( + def.into(), + Substitution::empty(Interner), + db.trait_environment_for_body(def.into()), + )?; + let c = interpret_mir(db, &body, false).0?; Ok(c) } @@ -209,9 +257,13 @@ pub(crate) fn const_eval_discriminant_variant( }; return Ok(value); } - let mir_body = db.mir_body(def)?; - let c = interpret_mir(db, &mir_body, false)?; - let c = try_const_usize(&c).unwrap() as i128; + let mir_body = db.monomorphized_mir_body( + def, + Substitution::empty(Interner), + db.trait_environment_for_body(def), + )?; + let c = interpret_mir(db, &mir_body, false).0?; + let c = try_const_usize(db, &c).unwrap() as i128; Ok(c) } @@ -226,15 +278,16 @@ pub(crate) fn eval_to_const( debruijn: DebruijnIndex, ) -> Const { let db = ctx.db; + let infer = ctx.clone().resolve_all(); if let Expr::Path(p) = &ctx.body.exprs[expr] { let resolver = &ctx.resolver; - if let Some(c) = path_to_const(db, resolver, p.mod_path(), mode, args, debruijn) { + if let Some(c) = path_to_const(db, resolver, p, mode, args, debruijn, infer[expr].clone()) { return c; } } let infer = ctx.clone().resolve_all(); if let Ok(mir_body) = lower_to_mir(ctx.db, ctx.owner, &ctx.body, &infer, expr) { - if let Ok(result) = interpret_mir(db, &mir_body, true) { + if let Ok(result) = interpret_mir(db, &mir_body, true).0 { return result; } } |