mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-02 14:51:48 +00:00
Support evaluating inherent associated constants with generics
This commit is contained in:
parent
3303a6eff5
commit
8a3ad7c3d5
7 changed files with 22 additions and 33 deletions
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue