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.rs97
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;
}
}