Unnamed repository; edit this file 'description' to name the repository.
Support evaluating inherent associated constants with generics
hkalbasi 2023-03-21
parent 3303a6e · commit 8a3ad7c
-rw-r--r--crates/hir-ty/src/consteval.rs10
-rw-r--r--crates/hir-ty/src/consteval/tests.rs8
-rw-r--r--crates/hir-ty/src/db.rs2
-rw-r--r--crates/hir-ty/src/infer/expr.rs15
-rw-r--r--crates/hir-ty/src/mir/eval.rs5
-rw-r--r--crates/hir-ty/src/mir/lower.rs11
-rw-r--r--crates/hir/src/lib.rs4
7 files changed, 22 insertions, 33 deletions
diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs
index fcb3445a54..7e69971fee 100644
--- a/crates/hir-ty/src/consteval.rs
+++ b/crates/hir-ty/src/consteval.rs
@@ -15,7 +15,7 @@ use stdx::never;
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,
+ Interner, MemoryMap, Substitution, Ty, TyBuilder,
};
use super::mir::{interpret_mir, lower_to_mir, pad16, MirEvalError, MirLowerError};
@@ -169,6 +169,7 @@ pub(crate) fn const_eval_recover(
_: &dyn HirDatabase,
_: &[String],
_: &ConstId,
+ _: &Substitution,
) -> Result<Const, ConstEvalError> {
Err(ConstEvalError::MirLowerError(MirLowerError::Loop))
}
@@ -184,10 +185,11 @@ pub(crate) fn const_eval_discriminant_recover(
pub(crate) fn const_eval_query(
db: &dyn HirDatabase,
const_id: ConstId,
+ subst: Substitution,
) -> Result<Const, ConstEvalError> {
let def = const_id.into();
let body = db.mir_body(def)?;
- let c = interpret_mir(db, &body, false)?;
+ let c = interpret_mir(db, &body, subst, false)?;
Ok(c)
}
@@ -210,7 +212,7 @@ 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 = interpret_mir(db, &mir_body, Substitution::empty(Interner), false)?;
let c = try_const_usize(&c).unwrap() as i128;
Ok(c)
}
@@ -234,7 +236,7 @@ pub(crate) fn eval_to_const(
}
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, Substitution::empty(Interner), true) {
return result;
}
}
diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs
index 47ef26fc58..a0efc7541e 100644
--- a/crates/hir-ty/src/consteval/tests.rs
+++ b/crates/hir-ty/src/consteval/tests.rs
@@ -1,4 +1,5 @@
use base_db::fixture::WithFixture;
+use chalk_ir::Substitution;
use hir_def::db::DefDatabase;
use crate::{
@@ -64,7 +65,7 @@ fn eval_goal(ra_fixture: &str) -> Result<Const, ConstEvalError> {
_ => None,
})
.unwrap();
- db.const_eval(const_id)
+ db.const_eval(const_id, Substitution::empty(Interner))
}
#[test]
@@ -1519,8 +1520,7 @@ fn const_generic_subst_fn() {
#[test]
fn const_generic_subst_assoc_const_impl() {
- // FIXME: this should evaluate to 5
- check_fail(
+ check_number(
r#"
struct Adder<const N: usize, const M: usize>;
impl<const N: usize, const M: usize> Adder<N, M> {
@@ -1528,7 +1528,7 @@ fn const_generic_subst_assoc_const_impl() {
}
const GOAL: usize = Adder::<2, 3>::VAL;
"#,
- ConstEvalError::MirEvalError(MirEvalError::TypeError("missing generic arg")),
+ 5,
);
}
diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs
index 8f1af4c2f8..000944e0b5 100644
--- a/crates/hir-ty/src/db.rs
+++ b/crates/hir-ty/src/db.rs
@@ -57,7 +57,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
#[salsa::invoke(crate::consteval::const_eval_query)]
#[salsa::cycle(crate::consteval::const_eval_recover)]
- fn const_eval(&self, def: ConstId) -> Result<Const, ConstEvalError>;
+ fn const_eval(&self, def: ConstId, subst: Substitution) -> Result<Const, ConstEvalError>;
#[salsa::invoke(crate::consteval::const_eval_discriminant_variant)]
#[salsa::cycle(crate::consteval::const_eval_discriminant_recover)]
diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs
index d14b3f7140..d52188bb28 100644
--- a/crates/hir-ty/src/infer/expr.rs
+++ b/crates/hir-ty/src/infer/expr.rs
@@ -612,21 +612,6 @@ impl<'a> InferenceContext<'a> {
let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
self.resolve_associated_type(inner_ty, self.resolve_future_future_output())
}
- // Expr::Try { expr } => {
- // let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
- // if let Some(trait_) = self.resolve_lang_trait(LangItem::Try) {
- // if let Some(func) = self.db.trait_data(trait_).method_by_name(&name!(branch)) {
- // let subst = TyBuilder::subst_for_def(self.db, trait_, None)
- // .push(inner_ty.clone())
- // .build();
- // self.write_method_resolution(tgt_expr, func, subst.clone());
- // }
- // let try_output = self.resolve_output_on(trait_);
- // self.resolve_associated_type(inner_ty, try_output)
- // } else {
- // self.err_ty()
- // }
- // }
Expr::Cast { expr, type_ref } => {
let cast_ty = self.make_ty(type_ref);
// FIXME: propagate the "castable to" expectation
diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs
index 26bf877cf0..7b83645fae 100644
--- a/crates/hir-ty/src/mir/eval.rs
+++ b/crates/hir-ty/src/mir/eval.rs
@@ -282,6 +282,7 @@ struct Locals<'a> {
pub fn interpret_mir(
db: &dyn HirDatabase,
body: &MirBody,
+ subst: Substitution,
// FIXME: This is workaround. Ideally, const generics should have a separate body (issue #7434), but now
// they share their body with their parent, so in MIR lowering we have locals of the parent body, which
// might have placeholders. With this argument, we (wrongly) assume that every placeholder type has
@@ -291,11 +292,11 @@ pub fn interpret_mir(
) -> Result<Const> {
let ty = body.locals[return_slot()].ty.clone();
let mut evaluator = Evaluator::new(db, body, assert_placeholder_ty_is_unused);
- let bytes = evaluator.interpret_mir_with_no_arg(&body)?;
+ let bytes = evaluator.interpret_mir(&body, None.into_iter(), subst.clone())?;
let memory_map = evaluator.create_memory_map(
&bytes,
&ty,
- &Locals { ptr: &ArenaMap::new(), body: &body, subst: &Substitution::empty(Interner) },
+ &Locals { ptr: &ArenaMap::new(), body: &body, subst: &subst },
)?;
return Ok(intern_const_scalar(ConstScalar::Bytes(bytes, memory_map), ty));
}
diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs
index 65e3348b21..1821796be3 100644
--- a/crates/hir-ty/src/mir/lower.rs
+++ b/crates/hir-ty/src/mir/lower.rs
@@ -231,13 +231,13 @@ impl MirLowerCtx<'_> {
let pr = match pr {
ResolveValueResult::ValueNs(v) => v,
ResolveValueResult::Partial(..) => {
- if let Some(assoc) = self
+ if let Some((assoc, subst)) = self
.infer
.assoc_resolutions_for_expr(expr_id)
{
- match assoc.0 {
+ match assoc {
hir_def::AssocItemId::ConstId(c) => {
- self.lower_const(c, current, place, expr_id.into())?;
+ self.lower_const(c, current, place, subst, expr_id.into())?;
return Ok(Some(current))
},
hir_def::AssocItemId::FunctionId(_) => {
@@ -274,7 +274,7 @@ impl MirLowerCtx<'_> {
Ok(Some(current))
}
ValueNs::ConstId(const_id) => {
- self.lower_const(const_id, current, place, expr_id.into())?;
+ self.lower_const(const_id, current, place, Substitution::empty(Interner), expr_id.into())?;
Ok(Some(current))
}
ValueNs::EnumVariantId(variant_id) => {
@@ -951,9 +951,10 @@ impl MirLowerCtx<'_> {
const_id: hir_def::ConstId,
prev_block: BasicBlockId,
place: Place,
+ subst: Substitution,
span: MirSpan,
) -> Result<()> {
- let c = self.db.const_eval(const_id)?;
+ let c = self.db.const_eval(const_id, subst)?;
self.write_const_to_place(c, prev_block, place, span)
}
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 35424feec8..dbf618afa6 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -1801,7 +1801,7 @@ impl Function {
let body = db
.mir_body(self.id.into())
.map_err(|e| MirEvalError::MirLowerError(self.id.into(), e))?;
- interpret_mir(db, &body, false)?;
+ interpret_mir(db, &body, Substitution::empty(Interner), false)?;
Ok(())
}
}
@@ -1947,7 +1947,7 @@ impl Const {
}
pub fn render_eval(self, db: &dyn HirDatabase) -> Result<String, ConstEvalError> {
- let c = db.const_eval(self.id)?;
+ let c = db.const_eval(self.id, Substitution::empty(Interner))?;
let r = format!("{}", HexifiedConst(c).display(db));
// We want to see things like `<utf8-error>` and `<layout-error>` as they are probably bug in our
// implementation, but there is no need to show things like `<enum-not-supported>` or `<ref-not-supported>` to