Unnamed repository; edit this file 'description' to name the repository.
Auto merge of #15228 - HKalbasi:mir, r=HKalbasi
Implement recursion in mir interpreter without recursion This enables interpreting functions with deep stack + profiling. I also applied some changes to make it faster based on the profiling result.
bors 2023-07-07
parent 954a341 · parent 4a444e7 · commit c5ca816
-rw-r--r--crates/hir-def/src/db.rs5
-rw-r--r--crates/hir-def/src/lang_item.rs8
-rw-r--r--crates/hir-ty/src/chalk_db.rs4
-rw-r--r--crates/hir-ty/src/consteval.rs8
-rw-r--r--crates/hir-ty/src/consteval/tests.rs4
-rw-r--r--crates/hir-ty/src/db.rs8
-rw-r--r--crates/hir-ty/src/lower.rs4
-rw-r--r--crates/hir-ty/src/method_resolution.rs2
-rw-r--r--crates/hir-ty/src/mir/eval.rs617
-rw-r--r--crates/hir-ty/src/mir/eval/shim.rs24
-rw-r--r--crates/hir-ty/src/mir/eval/shim/simd.rs2
-rw-r--r--crates/hir-ty/src/mir/eval/tests.rs2
-rw-r--r--crates/hir-ty/src/mir/lower/as_place.rs4
-rw-r--r--crates/hir/src/lib.rs2
-rw-r--r--crates/hir/src/source_analyzer.rs2
15 files changed, 432 insertions, 264 deletions
diff --git a/crates/hir-def/src/db.rs b/crates/hir-def/src/db.rs
index 33c3a59db2..82e6dfb30c 100644
--- a/crates/hir-def/src/db.rs
+++ b/crates/hir-def/src/db.rs
@@ -18,7 +18,7 @@ use crate::{
generics::GenericParams,
import_map::ImportMap,
item_tree::{AttrOwner, ItemTree},
- lang_item::{LangItem, LangItemTarget, LangItems},
+ lang_item::{self, LangItem, LangItemTarget, LangItems},
nameres::{diagnostics::DefDiagnostic, DefMap},
visibility::{self, Visibility},
AttrDefId, BlockId, BlockLoc, ConstBlockId, ConstBlockLoc, ConstId, ConstLoc, DefWithBodyId,
@@ -204,6 +204,9 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDataba
#[salsa::invoke(AttrsWithOwner::attrs_query)]
fn attrs(&self, def: AttrDefId) -> Attrs;
+ #[salsa::invoke(lang_item::lang_attr_query)]
+ fn lang_attr(&self, def: AttrDefId) -> Option<LangItem>;
+
#[salsa::transparent]
#[salsa::invoke(AttrsWithOwner::attrs_with_owner)]
fn attrs_with_owner(&self, def: AttrDefId) -> AttrsWithOwner;
diff --git a/crates/hir-def/src/lang_item.rs b/crates/hir-def/src/lang_item.rs
index 0e9ac58fba..627479bb7c 100644
--- a/crates/hir-def/src/lang_item.rs
+++ b/crates/hir-def/src/lang_item.rs
@@ -180,15 +180,15 @@ impl LangItems {
T: Into<AttrDefId> + Copy,
{
let _p = profile::span("collect_lang_item");
- if let Some(lang_item) = lang_attr(db, item) {
+ if let Some(lang_item) = db.lang_attr(item.into()) {
self.items.entry(lang_item).or_insert_with(|| constructor(item));
}
}
}
-pub fn lang_attr(db: &dyn DefDatabase, item: impl Into<AttrDefId> + Copy) -> Option<LangItem> {
- let attrs = db.attrs(item.into());
- attrs.by_key("lang").string_value().cloned().and_then(|it| LangItem::from_str(&it))
+pub(crate) fn lang_attr_query(db: &dyn DefDatabase, item: AttrDefId) -> Option<LangItem> {
+ let attrs = db.attrs(item);
+ attrs.by_key("lang").string_value().and_then(|it| LangItem::from_str(&it))
}
pub enum GenericRequirement {
diff --git a/crates/hir-ty/src/chalk_db.rs b/crates/hir-ty/src/chalk_db.rs
index 0038b0d183..50eabc867b 100644
--- a/crates/hir-ty/src/chalk_db.rs
+++ b/crates/hir-ty/src/chalk_db.rs
@@ -11,7 +11,7 @@ use chalk_solve::rust_ir::{self, OpaqueTyDatumBound, WellKnownTrait};
use base_db::CrateId;
use hir_def::{
hir::Movability,
- lang_item::{lang_attr, LangItem, LangItemTarget},
+ lang_item::{LangItem, LangItemTarget},
AssocItemId, BlockId, GenericDefId, HasModule, ItemContainerId, Lookup, TypeAliasId,
};
use hir_expand::name::name;
@@ -565,7 +565,7 @@ pub(crate) fn trait_datum_query(
let where_clauses = convert_where_clauses(db, trait_.into(), &bound_vars);
let associated_ty_ids = trait_data.associated_types().map(to_assoc_type_id).collect();
let trait_datum_bound = rust_ir::TraitDatumBound { where_clauses };
- let well_known = lang_attr(db.upcast(), trait_).and_then(well_known_trait_from_lang_item);
+ let well_known = db.lang_attr(trait_.into()).and_then(well_known_trait_from_lang_item);
let trait_datum = TraitDatum {
id: trait_id,
binders: make_binders(db, &generic_params, trait_datum_bound),
diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs
index 537e28894a..4de90d40a7 100644
--- a/crates/hir-ty/src/consteval.rs
+++ b/crates/hir-ty/src/consteval.rs
@@ -228,7 +228,7 @@ pub(crate) fn const_eval_query(
}
GeneralConstId::InTypeConstId(c) => db.mir_body(c.into())?,
};
- let c = interpret_mir(db, &body, false).0?;
+ let c = interpret_mir(db, body, false).0?;
Ok(c)
}
@@ -241,7 +241,7 @@ pub(crate) fn const_eval_static_query(
Substitution::empty(Interner),
db.trait_environment_for_body(def.into()),
)?;
- let c = interpret_mir(db, &body, false).0?;
+ let c = interpret_mir(db, body, false).0?;
Ok(c)
}
@@ -268,7 +268,7 @@ pub(crate) fn const_eval_discriminant_variant(
Substitution::empty(Interner),
db.trait_environment_for_body(def),
)?;
- let c = interpret_mir(db, &mir_body, false).0?;
+ let c = interpret_mir(db, mir_body, false).0?;
let c = try_const_usize(db, &c).unwrap() as i128;
Ok(c)
}
@@ -293,7 +293,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).0 {
+ if let Ok(result) = interpret_mir(db, Arc::new(mir_body), true).0 {
return result;
}
}
diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs
index d5feb6c7fe..35ecb89824 100644
--- a/crates/hir-ty/src/consteval/tests.rs
+++ b/crates/hir-ty/src/consteval/tests.rs
@@ -16,7 +16,7 @@ mod intrinsics;
fn simplify(e: ConstEvalError) -> ConstEvalError {
match e {
- ConstEvalError::MirEvalError(MirEvalError::InFunction(_, e, _, _)) => {
+ ConstEvalError::MirEvalError(MirEvalError::InFunction(e, _)) => {
simplify(ConstEvalError::MirEvalError(*e))
}
_ => e,
@@ -2471,7 +2471,7 @@ fn exec_limits() {
}
const GOAL: i32 = f(0);
"#,
- |e| e == ConstEvalError::MirEvalError(MirEvalError::StackOverflow),
+ |e| e == ConstEvalError::MirEvalError(MirEvalError::ExecutionLimitExceeded),
);
// Reasonable code should still work
check_number(
diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs
index 9dd810f844..14b719ea41 100644
--- a/crates/hir-ty/src/db.rs
+++ b/crates/hir-ty/src/db.rs
@@ -110,6 +110,14 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
#[salsa::invoke(crate::layout::target_data_layout_query)]
fn target_data_layout(&self, krate: CrateId) -> Option<Arc<TargetDataLayout>>;
+ #[salsa::invoke(crate::method_resolution::lookup_impl_method_query)]
+ fn lookup_impl_method(
+ &self,
+ env: Arc<crate::TraitEnvironment>,
+ func: FunctionId,
+ fn_subst: Substitution,
+ ) -> (FunctionId, Substitution);
+
#[salsa::invoke(crate::lower::callable_item_sig)]
fn callable_item_signature(&self, def: CallableDefId) -> PolyFnSig;
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index e21f77a2d7..2837f400bc 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -23,7 +23,7 @@ use hir_def::{
generics::{
TypeOrConstParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget,
},
- lang_item::{lang_attr, LangItem},
+ lang_item::LangItem,
nameres::MacroSubNs,
path::{GenericArg, GenericArgs, ModPath, Path, PathKind, PathSegment, PathSegments},
resolver::{HasResolver, Resolver, TypeNs},
@@ -1012,7 +1012,7 @@ impl<'a> TyLoweringContext<'a> {
// (So ideally, we'd only ignore `~const Drop` here)
// - `Destruct` impls are built-in in 1.62 (current nightly as of 08-04-2022), so until
// the builtin impls are supported by Chalk, we ignore them here.
- if let Some(lang) = lang_attr(self.db.upcast(), tr.hir_trait_id()) {
+ if let Some(lang) = self.db.lang_attr(tr.hir_trait_id().into()) {
if matches!(lang, LangItem::Drop | LangItem::Destruct) {
return false;
}
diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs
index 5781ea48ee..5e1040bc6a 100644
--- a/crates/hir-ty/src/method_resolution.rs
+++ b/crates/hir-ty/src/method_resolution.rs
@@ -682,7 +682,7 @@ pub fn is_dyn_method(
/// Looks up the impl method that actually runs for the trait method `func`.
///
/// Returns `func` if it's not a method defined in a trait or the lookup failed.
-pub fn lookup_impl_method(
+pub(crate) fn lookup_impl_method_query(
db: &dyn HirDatabase,
env: Arc<TraitEnvironment>,
func: FunctionId,
diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs
index 299efb7145..c76d066232 100644
--- a/crates/hir-ty/src/mir/eval.rs
+++ b/crates/hir-ty/src/mir/eval.rs
@@ -1,6 +1,6 @@
//! This module provides a MIR interpreter, which is used in const eval.
-use std::{borrow::Cow, collections::HashMap, fmt::Write, iter, ops::Range};
+use std::{borrow::Cow, cell::RefCell, collections::HashMap, fmt::Write, iter, mem, ops::Range};
use base_db::{CrateId, FileId};
use chalk_ir::Mutability;
@@ -8,7 +8,7 @@ use either::Either;
use hir_def::{
builtin_type::BuiltinType,
data::adt::{StructFlags, VariantData},
- lang_item::{lang_attr, LangItem},
+ lang_item::LangItem,
layout::{TagEncoding, Variants},
AdtId, DefWithBodyId, EnumVariantId, FunctionId, HasModule, ItemContainerId, Lookup, StaticId,
VariantId,
@@ -28,7 +28,7 @@ use crate::{
infer::PointerCast,
layout::{Layout, LayoutError, RustcEnumVariantIdx},
mapping::from_chalk,
- method_resolution::{is_dyn_method, lookup_impl_method},
+ method_resolution::is_dyn_method,
name, static_lifetime,
traits::FnTrait,
utils::{detect_variant_from_bytes, ClosureSubst},
@@ -37,8 +37,8 @@ use crate::{
};
use super::{
- return_slot, AggregateKind, BinOp, CastKind, LocalId, MirBody, MirLowerError, MirSpan, Operand,
- Place, ProjectionElem, Rvalue, StatementKind, TerminatorKind, UnOp,
+ return_slot, AggregateKind, BasicBlockId, BinOp, CastKind, LocalId, MirBody, MirLowerError,
+ MirSpan, Operand, Place, ProjectionElem, Rvalue, StatementKind, TerminatorKind, UnOp,
};
mod shim;
@@ -114,11 +114,20 @@ impl TlsData {
}
}
+struct StackFrame {
+ body: Arc<MirBody>,
+ locals: Locals,
+ destination: Option<BasicBlockId>,
+ prev_stack_ptr: usize,
+ span: (MirSpan, DefWithBodyId),
+}
+
pub struct Evaluator<'a> {
db: &'a dyn HirDatabase,
trait_env: Arc<TraitEnvironment>,
stack: Vec<u8>,
heap: Vec<u8>,
+ code_stack: Vec<StackFrame>,
/// Stores the global location of the statics. We const evaluate every static first time we need it
/// and see it's missing, then we add it to this to reuse.
static_locations: FxHashMap<StaticId, Address>,
@@ -129,6 +138,7 @@ pub struct Evaluator<'a> {
thread_local_storage: TlsData,
stdout: Vec<u8>,
stderr: Vec<u8>,
+ layout_cache: RefCell<FxHashMap<Ty, Arc<Layout>>>,
crate_id: CrateId,
// FIXME: This is a workaround, see the comment on `interpret_mir`
assert_placeholder_ty_is_unused: bool,
@@ -192,7 +202,7 @@ impl IntervalAndTy {
addr: Address,
ty: Ty,
evaluator: &Evaluator<'_>,
- locals: &Locals<'_>,
+ locals: &Locals,
) -> Result<IntervalAndTy> {
let size = evaluator.size_of_sized(&ty, locals, "type of interval")?;
Ok(IntervalAndTy { interval: Interval { addr, size }, ty })
@@ -292,7 +302,7 @@ pub enum MirEvalError {
TypeIsUnsized(Ty, &'static str),
NotSupported(String),
InvalidConst(Const),
- InFunction(Either<FunctionId, ClosureId>, Box<MirEvalError>, MirSpan, DefWithBodyId),
+ InFunction(Box<MirEvalError>, Vec<(Either<FunctionId, ClosureId>, MirSpan, DefWithBodyId)>),
ExecutionLimitExceeded,
StackOverflow,
TargetDataLayoutNotAvailable,
@@ -310,40 +320,42 @@ impl MirEvalError {
) -> std::result::Result<(), std::fmt::Error> {
writeln!(f, "Mir eval error:")?;
let mut err = self;
- while let MirEvalError::InFunction(func, e, span, def) = err {
+ while let MirEvalError::InFunction(e, stack) = err {
err = e;
- match func {
- Either::Left(func) => {
- let function_name = db.function_data(*func);
- writeln!(
- f,
- "In function {} ({:?})",
- function_name.name.display(db.upcast()),
- func
- )?;
- }
- Either::Right(clos) => {
- writeln!(f, "In {:?}", clos)?;
+ for (func, span, def) in stack.iter().take(30).rev() {
+ match func {
+ Either::Left(func) => {
+ let function_name = db.function_data(*func);
+ writeln!(
+ f,
+ "In function {} ({:?})",
+ function_name.name.display(db.upcast()),
+ func
+ )?;
+ }
+ Either::Right(clos) => {
+ writeln!(f, "In {:?}", clos)?;
+ }
}
+ let source_map = db.body_with_source_map(*def).1;
+ let span: InFile<SyntaxNodePtr> = match span {
+ MirSpan::ExprId(e) => match source_map.expr_syntax(*e) {
+ Ok(s) => s.map(|it| it.into()),
+ Err(_) => continue,
+ },
+ MirSpan::PatId(p) => match source_map.pat_syntax(*p) {
+ Ok(s) => s.map(|it| match it {
+ Either::Left(e) => e.into(),
+ Either::Right(e) => e.into(),
+ }),
+ Err(_) => continue,
+ },
+ MirSpan::Unknown => continue,
+ };
+ let file_id = span.file_id.original_file(db.upcast());
+ let text_range = span.value.text_range();
+ writeln!(f, "{}", span_formatter(file_id, text_range))?;
}
- let source_map = db.body_with_source_map(*def).1;
- let span: InFile<SyntaxNodePtr> = match span {
- MirSpan::ExprId(e) => match source_map.expr_syntax(*e) {
- Ok(s) => s.map(|it| it.into()),
- Err(_) => continue,
- },
- MirSpan::PatId(p) => match source_map.pat_syntax(*p) {
- Ok(s) => s.map(|it| match it {
- Either::Left(e) => e.into(),
- Either::Right(e) => e.into(),
- }),
- Err(_) => continue,
- },
- MirSpan::Unknown => continue,
- };
- let file_id = span.file_id.original_file(db.upcast());
- let text_range = span.value.text_range();
- writeln!(f, "{}", span_formatter(file_id, text_range))?;
}
match err {
MirEvalError::InFunction(..) => unreachable!(),
@@ -423,13 +435,7 @@ impl std::fmt::Debug for MirEvalError {
let data = &arg0.data(Interner);
f.debug_struct("InvalidConst").field("ty", &data.ty).field("value", &arg0).finish()
}
- Self::InFunction(func, e, span, _) => {
- let mut e = &**e;
- let mut stack = vec![(*func, *span)];
- while let Self::InFunction(f, next_e, span, _) = e {
- e = &next_e;
- stack.push((*f, *span));
- }
+ Self::InFunction(e, stack) => {
f.debug_struct("WithStack").field("error", e).field("stack", &stack).finish()
}
}
@@ -459,15 +465,15 @@ impl DropFlags {
}
#[derive(Debug)]
-struct Locals<'a> {
- ptr: &'a ArenaMap<LocalId, Interval>,
- body: &'a MirBody,
+struct Locals {
+ ptr: ArenaMap<LocalId, Interval>,
+ body: Arc<MirBody>,
drop_flags: DropFlags,
}
pub fn interpret_mir(
db: &dyn HirDatabase,
- body: &MirBody,
+ body: Arc<MirBody>,
// 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
@@ -476,16 +482,16 @@ pub fn interpret_mir(
assert_placeholder_ty_is_unused: bool,
) -> (Result<Const>, String, String) {
let ty = body.locals[return_slot()].ty.clone();
- let mut evaluator = Evaluator::new(db, body, assert_placeholder_ty_is_unused);
+ let mut evaluator = Evaluator::new(db, &body, assert_placeholder_ty_is_unused);
let it: Result<Const> = (|| {
if evaluator.ptr_size() != std::mem::size_of::<usize>() {
not_supported!("targets with different pointer size from host");
}
- let bytes = evaluator.interpret_mir(&body, None.into_iter())?;
+ let bytes = evaluator.interpret_mir(body.clone(), None.into_iter())?;
let mut memory_map = evaluator.create_memory_map(
&bytes,
&ty,
- &Locals { ptr: &ArenaMap::new(), body: &body, drop_flags: DropFlags::default() },
+ &Locals { ptr: ArenaMap::new(), body, drop_flags: DropFlags::default() },
)?;
memory_map.vtable = evaluator.vtable_map.clone();
return Ok(intern_const_scalar(ConstScalar::Bytes(bytes, memory_map), ty));
@@ -508,6 +514,7 @@ impl Evaluator<'_> {
Evaluator {
stack: vec![0],
heap: vec![0],
+ code_stack: vec![],
vtable_map: VTableMap::default(),
thread_local_storage: TlsData::default(),
static_locations: HashMap::default(),
@@ -519,14 +526,15 @@ impl Evaluator<'_> {
assert_placeholder_ty_is_unused,
stack_depth_limit: 100,
execution_limit: 1000_000,
+ layout_cache: RefCell::new(HashMap::default()),
}
}
- fn place_addr(&self, p: &Place, locals: &Locals<'_>) -> Result<Address> {
+ fn place_addr(&self, p: &Place, locals: &Locals) -> Result<Address> {
Ok(self.place_addr_and_ty_and_metadata(p, locals)?.0)
}
- fn place_interval(&self, p: &Place, locals: &Locals<'_>) -> Result<Interval> {
+ fn place_interval(&self, p: &Place, locals: &Locals) -> Result<Interval> {
let place_addr_and_ty = self.place_addr_and_ty_and_metadata(p, locals)?;
Ok(Interval {
addr: place_addr_and_ty.0,
@@ -548,7 +556,7 @@ impl Evaluator<'_> {
fn place_addr_and_ty_and_metadata<'a>(
&'a self,
p: &Place,
- locals: &'a Locals<'a>,
+ locals: &'a Locals,
) -> Result<(Address, Ty, Option<IntervalOrOwned>)> {
let mut addr = locals.ptr[p.local].addr;
let mut ty: Ty = locals.body.locals[p.local].ty.clone();
@@ -675,9 +683,15 @@ impl Evaluator<'_> {
}
fn layout(&self, ty: &Ty) -> Result<Arc<Layout>> {
- self.db
+ if let Some(x) = self.layout_cache.borrow().get(ty) {
+ return Ok(x.clone());
+ }
+ let r = self
+ .db
.layout_of_ty(ty.clone(), self.crate_id)
- .map_err(|e| MirEvalError::LayoutError(e, ty.clone()))
+ .map_err(|e| MirEvalError::LayoutError(e, ty.clone()))?;
+ self.layout_cache.borrow_mut().insert(ty.clone(), r.clone());
+ Ok(r)
}
fn layout_adt(&self, adt: AdtId, subst: Substitution) -> Result<Arc<Layout>> {
@@ -686,11 +700,11 @@ impl Evaluator<'_> {
})
}
- fn place_ty<'a>(&'a self, p: &Place, locals: &'a Locals<'a>) -> Result<Ty> {
+ fn place_ty<'a>(&'a self, p: &Place, locals: &'a Locals) -> Result<Ty> {
Ok(self.place_addr_and_ty_and_metadata(p, locals)?.1)
}
- fn operand_ty(&self, o: &Operand, locals: &Locals<'_>) -> Result<Ty> {
+ fn operand_ty(&self, o: &Operand, locals: &Locals) -> Result<Ty> {
Ok(match o {
Operand::Copy(p) | Operand::Move(p) => self.place_ty(p, locals)?,
Operand::Constant(c) => c.data(Interner).ty.clone(),
@@ -701,11 +715,7 @@ impl Evaluator<'_> {
})
}
- fn operand_ty_and_eval(
- &mut self,
- o: &Operand,
- locals: &mut Locals<'_>,
- ) -> Result<IntervalAndTy> {
+ fn operand_ty_and_eval(&mut self, o: &Operand, locals: &mut Locals) -> Result<IntervalAndTy> {
Ok(IntervalAndTy {
interval: self.eval_operand(o, locals)?,
ty: self.operand_ty(o, locals)?,
@@ -714,8 +724,8 @@ impl Evaluator<'_> {
fn interpret_mir(
&mut self,
- body: &MirBody,
- args: impl Iterator<Item = Vec<u8>>,
+ body: Arc<MirBody>,
+ args: impl Iterator<Item = IntervalOrOwned>,
) -> Result<Vec<u8>> {
if let Some(it) = self.stack_depth_limit.checked_sub(1) {
self.stack_depth_limit = it;
@@ -723,14 +733,192 @@ impl Evaluator<'_> {
return Err(MirEvalError::StackOverflow);
}
let mut current_block_idx = body.start_block;
+ let (mut locals, prev_stack_ptr) = self.create_locals_for_body(body.clone(), None)?;
+ self.fill_locals_for_body(&body, &mut locals, args)?;
+ let prev_code_stack = mem::take(&mut self.code_stack);
+ let span = (MirSpan::Unknown, body.owner);
+ self.code_stack.push(StackFrame { body, locals, destination: None, prev_stack_ptr, span });
+ 'stack: loop {
+ let Some(mut my_stack_frame) = self.code_stack.pop() else {
+ not_supported!("missing stack frame");
+ };
+ let e = (|| {
+ let mut locals = &mut my_stack_frame.locals;
+ let body = &*my_stack_frame.body;
+ loop {
+ let current_block = &body.basic_blocks[current_block_idx];
+ if let Some(it) = self.execution_limit.checked_sub(1) {
+ self.execution_limit = it;
+ } else {
+ return Err(MirEvalError::ExecutionLimitExceeded);
+ }
+ for statement in &current_block.statements {
+ match &statement.kind {
+ StatementKind::Assign(l, r) => {
+ let addr = self.place_addr(l, &locals)?;
+ let result = self.eval_rvalue(r, &mut locals)?.to_vec(&self)?;
+ self.write_memory(addr, &result)?;
+ locals.drop_flags.add_place(l.clone());
+ }
+ StatementKind::Deinit(_) => not_supported!("de-init statement"),
+ StatementKind::StorageLive(_)
+ | StatementKind::StorageDead(_)
+ | StatementKind::Nop => (),
+ }
+ }
+ let Some(terminator) = current_block.terminator.as_ref() else {
+ not_supported!("block without terminator");
+ };
+ match &terminator.kind {
+ TerminatorKind::Goto { target } => {
+ current_block_idx = *target;
+ }
+ TerminatorKind::Call {
+ func,
+ args,
+ destination,
+ target,
+ cleanup: _,
+ from_hir_call: _,
+ } => {
+ let destination_interval = self.place_interval(destination, &locals)?;
+ let fn_ty = self.operand_ty(func, &locals)?;
+ let args = args
+ .iter()
+ .map(|it| self.operand_ty_and_eval(it, &mut locals))
+ .collect::<Result<Vec<_>>>()?;
+ let stack_frame = match &fn_ty.data(Interner).kind {
+ TyKind::Function(_) => {
+ let bytes = self.eval_operand(func, &mut locals)?;
+ self.exec_fn_pointer(
+ bytes,
+ destination_interval,
+ &args,
+ &locals,
+ *target,
+ terminator.span,
+ )?
+ }
+ TyKind::FnDef(def, generic_args) => self.exec_fn_def(
+ *def,
+ generic_args,
+ destination_interval,
+ &args,
+ &locals,
+ *target,
+ terminator.span,
+ )?,
+ it => not_supported!("unknown function type {it:?}"),
+ };
+ locals.drop_flags.add_place(destination.clone());
+ if let Some(stack_frame) = stack_frame {
+ self.code_stack.push(my_stack_frame);
+ current_block_idx = stack_frame.body.start_block;
+ self.code_stack.push(stack_frame);
+ return Ok(None);
+ } else {
+ current_block_idx =
+ target.ok_or(MirEvalError::UndefinedBehavior(
+ "Diverging function returned".to_owned(),
+ ))?;
+ }
+ }
+ TerminatorKind::SwitchInt { discr, targets } => {
+ let val = u128::from_le_bytes(pad16(
+ self.eval_operand(discr, &mut locals)?.get(&self)?,
+ false,
+ ));
+ current_block_idx = targets.target_for_value(val);
+ }
+ TerminatorKind::Return => {
+ break;
+ }
+ TerminatorKind::Unreachable => {
+ return Err(MirEvalError::UndefinedBehavior(
+ "unreachable executed".to_owned(),
+ ));
+ }
+ TerminatorKind::Drop { place, target, unwind: _ } => {
+ self.drop_place(place, &mut locals, terminator.span)?;
+ current_block_idx = *target;
+ }
+ _ => not_supported!("unknown terminator"),
+ }
+ }
+ Ok(Some(my_stack_frame))
+ })();
+ let my_stack_frame = match e {
+ Ok(None) => continue 'stack,
+ Ok(Some(x)) => x,
+ Err(e) => {
+ let my_code_stack = mem::replace(&mut self.code_stack, prev_code_stack);
+ let mut error_stack = vec![];
+ for frame in my_code_stack.into_iter().rev() {
+ if let DefWithBodyId::FunctionId(f) = frame.body.owner {
+ error_stack.push((Either::Left(f), frame.span.0, frame.span.1));
+ }
+ }
+ return Err(MirEvalError::InFunction(Box::new(e), error_stack));
+ }
+ };
+ match my_stack_frame.destination {
+ None => {
+ self.code_stack = prev_code_stack;
+ self.stack_depth_limit += 1;
+ return Ok(my_stack_frame.locals.ptr[return_slot()].get(self)?.to_vec());
+ }
+ Some(bb) => {
+ // We don't support const promotion, so we can't truncate the stack yet.
+ let _ = my_stack_frame.prev_stack_ptr;
+ // self.stack.truncate(my_stack_frame.prev_stack_ptr);
+ current_block_idx = bb;
+ }
+ }
+ }
+ }
+
+ fn fill_locals_for_body(
+ &mut self,
+ body: &MirBody,
+ locals: &mut Locals,
+ args: impl Iterator<Item = IntervalOrOwned>,
+ ) -> Result<()> {
+ let mut remain_args = body.param_locals.len();
+ for ((l, interval), value) in locals.ptr.iter().skip(1).zip(args) {
+ locals.drop_flags.add_place(l.into());
+ match value {
+ IntervalOrOwned::Owned(value) => interval.write_from_bytes(self, &value)?,
+ IntervalOrOwned::Borrowed(value) => interval.write_from_interval(self, value)?,
+ }
+ if remain_args == 0 {
+ return Err(MirEvalError::TypeError("more arguments provided"));
+ }
+ remain_args -= 1;
+ }
+ if remain_args > 0 {
+ return Err(MirEvalError::TypeError("not enough arguments provided"));
+ }
+ Ok(())
+ }
+
+ fn create_locals_for_body(
+ &mut self,
+ body: Arc<MirBody>,
+ destination: Option<Interval>,
+ ) -> Result<(Locals, usize)> {
let mut locals =
- Locals { ptr: &ArenaMap::new(), body: &body, drop_flags: DropFlags::default() };
+ Locals { ptr: ArenaMap::new(), body: body.clone(), drop_flags: DropFlags::default() };
let (locals_ptr, stack_size) = {
let mut stack_ptr = self.stack.len();
let addr = body
.locals
.iter()
.map(|(id, it)| {
+ if id == return_slot() {
+ if let Some(destination) = destination {
+ return Ok((id, destination));
+ }
+ }
let (size, align) = self.size_align_of_sized(
&it.ty,
&locals,
@@ -747,112 +935,13 @@ impl Evaluator<'_> {
let stack_size = stack_ptr - self.stack.len();
(addr, stack_size)
};
- locals.ptr = &locals_ptr;
+ locals.ptr = locals_ptr;
+ let prev_stack_pointer = self.stack.len();
self.stack.extend(iter::repeat(0).take(stack_size));
- let mut remain_args = body.param_locals.len();
- for ((l, interval), value) in locals_ptr.iter().skip(1).zip(args) {
- locals.drop_flags.add_place(l.into());
- interval.write_from_bytes(self, &value)?;
- if remain_args == 0 {
- return Err(MirEvalError::TypeError("more arguments provided"));
- }
- remain_args -= 1;
- }
- if remain_args > 0 {
- return Err(MirEvalError::TypeError("not enough arguments provided"));
- }
- loop {
- let current_block = &body.basic_blocks[current_block_idx];
- if let Some(it) = self.execution_limit.checked_sub(1) {
- self.execution_limit = it;
- } else {
- return Err(MirEvalError::ExecutionLimitExceeded);
- }
- for statement in &current_block.statements {
- match &statement.kind {
- StatementKind::Assign(l, r) => {
- let addr = self.place_addr(l, &locals)?;
- let result = self.eval_rvalue(r, &mut locals)?.to_vec(&self)?;
- self.write_memory(addr, &result)?;
- locals.drop_flags.add_place(l.clone());
- }
- StatementKind::Deinit(_) => not_supported!("de-init statement"),
- StatementKind::StorageLive(_)
- | StatementKind::StorageDead(_)
- | StatementKind::Nop => (),
- }
- }
- let Some(terminator) = current_block.terminator.as_ref() else {
- not_supported!("block without terminator");
- };
- match &terminator.kind {
- TerminatorKind::Goto { target } => {
- current_block_idx = *target;
- }
- TerminatorKind::Call {
- func,
- args,
- destination,
- target,
- cleanup: _,
- from_hir_call: _,
- } => {
- let destination_interval = self.place_interval(destination, &locals)?;
- let fn_ty = self.operand_ty(func, &locals)?;
- let args = args
- .iter()
- .map(|it| self.operand_ty_and_eval(it, &mut locals))
- .collect::<Result<Vec<_>>>()?;
- match &fn_ty.data(Interner).kind {
- TyKind::Function(_) => {
- let bytes = self.eval_operand(func, &mut locals)?;
- self.exec_fn_pointer(
- bytes,
- destination_interval,
- &args,
- &locals,
- terminator.span,
- )?;
- }
- TyKind::FnDef(def, generic_args) => {
- self.exec_fn_def(
- *def,
- generic_args,
- destination_interval,
- &args,
- &locals,
- terminator.span,
- )?;
- }
- it => not_supported!("unknown function type {it:?}"),
- }
- locals.drop_flags.add_place(destination.clone());
- current_block_idx = target.expect("broken mir, function without target");
- }
- TerminatorKind::SwitchInt { discr, targets } => {
- let val = u128::from_le_bytes(pad16(
- self.eval_operand(discr, &mut locals)?.get(&self)?,
- false,
- ));
- current_block_idx = targets.target_for_value(val);
- }
- TerminatorKind::Return => {
- self.stack_depth_limit += 1;
- return Ok(locals.ptr[return_slot()].get(self)?.to_vec());
- }
- TerminatorKind::Unreachable => {
- return Err(MirEvalError::UndefinedBehavior("unreachable executed".to_owned()));
- }
- TerminatorKind::Drop { place, target, unwind: _ } => {
- self.drop_place(place, &mut locals, terminator.span)?;
- current_block_idx = *target;
- }
- _ => not_supported!("unknown terminator"),
- }
- }
+ Ok((locals, prev_stack_pointer))
}
- fn eval_rvalue(&mut self, r: &Rvalue, locals: &mut Locals<'_>) -> Result<IntervalOrOwned> {
+ fn eval_rvalue(&mut self, r: &Rvalue, locals: &mut Locals) -> Result<IntervalOrOwned> {
use IntervalOrOwned::*;
Ok(match r {
Rvalue::Use(it) => Borrowed(self.eval_operand(it, locals)?),
@@ -1372,7 +1461,7 @@ impl Evaluator<'_> {
&mut self,
it: VariantId,
subst: Substitution,
- locals: &Locals<'_>,
+ locals: &Locals,
) -> Result<(usize, Arc<Layout>, Option<(usize, usize, i128)>)> {
let adt = it.adt_id();
if let DefWithBodyId::VariantId(f) = locals.body.owner {
@@ -1452,7 +1541,7 @@ impl Evaluator<'_> {
Ok(result)
}
- fn eval_operand(&mut self, it: &Operand, locals: &mut Locals<'_>) -> Result<Interval> {
+ fn eval_operand(&mut self, it: &Operand, locals: &mut Locals) -> Result<Interval> {
Ok(match it {
Operand::Copy(p) | Operand::Move(p) => {
locals.drop_flags.remove_place(p);
@@ -1482,7 +1571,7 @@ impl Evaluator<'_> {
&mut self,
c: &chalk_ir::ConcreteConst<Interner>,
ty: &Ty,
- locals: &Locals<'_>,
+ locals: &Locals,
konst: &chalk_ir::Const<Interner>,
) -> Result<Interval> {
Ok(match &c.interned {
@@ -1516,7 +1605,7 @@ impl Evaluator<'_> {
})
}
- fn eval_place(&mut self, p: &Place, locals: &Locals<'_>) -> Result<Interval> {
+ fn eval_place(&mut self, p: &Place, locals: &Locals) -> Result<Interval> {
let addr = self.place_addr(p, locals)?;
Ok(Interval::new(
addr,
@@ -1562,7 +1651,7 @@ impl Evaluator<'_> {
Ok(())
}
- fn size_align_of(&self, ty: &Ty, locals: &Locals<'_>) -> Result<Option<(usize, usize)>> {
+ fn size_align_of(&self, ty: &Ty, locals: &Locals) -> Result<Option<(usize, usize)>> {
if let DefWithBodyId::VariantId(f) = locals.body.owner {
if let Some((adt, _)) = ty.as_adt() {
if AdtId::from(f.parent) == adt {
@@ -1586,7 +1675,7 @@ impl Evaluator<'_> {
/// A version of `self.size_of` which returns error if the type is unsized. `what` argument should
/// be something that complete this: `error: type {ty} was unsized. {what} should be sized`
- fn size_of_sized(&self, ty: &Ty, locals: &Locals<'_>, what: &'static str) -> Result<usize> {
+ fn size_of_sized(&self, ty: &Ty, locals: &Locals, what: &'static str) -> Result<usize> {
match self.size_align_of(ty, locals)? {
Some(it) => Ok(it.0),
None => Err(MirEvalError::TypeIsUnsized(ty.clone(), what)),
@@ -1598,7 +1687,7 @@ impl Evaluator<'_> {
fn size_align_of_sized(
&self,
ty: &Ty,
- locals: &Locals<'_>,
+ locals: &Locals,
what: &'static str,
) -> Result<(usize, usize)> {
match self.size_align_of(ty, locals)? {
@@ -1621,7 +1710,7 @@ impl Evaluator<'_> {
let ItemContainerId::TraitId(parent) = self.db.lookup_intern_function(def).container else {
return None;
};
- let l = lang_attr(self.db.upcast(), parent)?;
+ let l = self.db.lang_attr(parent.into())?;
match l {
FnOnce => Some(FnTrait::FnOnce),
FnMut => Some(FnTrait::FnMut),
@@ -1630,12 +1719,12 @@ impl Evaluator<'_> {
}
}
- fn create_memory_map(&self, bytes: &[u8], ty: &Ty, locals: &Locals<'_>) -> Result<MemoryMap> {
+ fn create_memory_map(&self, bytes: &[u8], ty: &Ty, locals: &Locals) -> Result<MemoryMap> {
fn rec(
this: &Evaluator<'_>,
bytes: &[u8],
ty: &Ty,
- locals: &Locals<'_>,
+ locals: &Locals,
mm: &mut MemoryMap,
) -> Result<()> {
match ty.kind(Interner) {
@@ -1741,7 +1830,7 @@ impl Evaluator<'_> {
old_vtable: &VTableMap,
addr: Address,
ty: &Ty,
- locals: &Locals<'_>,
+ locals: &Locals,
) -> Result<()> {
// FIXME: support indirect references
let layout = self.layout(ty)?;
@@ -1815,21 +1904,21 @@ impl Evaluator<'_> {
bytes: Interval,
destination: Interval,
args: &[IntervalAndTy],
- locals: &Locals<'_>,
+ locals: &Locals,
+ target_bb: Option<BasicBlockId>,
span: MirSpan,
- ) -> Result<()> {
+ ) -> Result<Option<StackFrame>> {
let id = from_bytes!(usize, bytes.get(self)?);
let next_ty = self.vtable_map.ty(id)?.clone();
match &next_ty.data(Interner).kind {
TyKind::FnDef(def, generic_args) => {
- self.exec_fn_def(*def, generic_args, destination, args, &locals, span)?;
+ self.exec_fn_def(*def, generic_args, destination, args, &locals, target_bb, span)
}
TyKind::Closure(id, subst) => {
- self.exec_closure(*id, bytes.slice(0..0), subst, destination, args, locals, span)?;
+ self.exec_closure(*id, bytes.slice(0..0), subst, destination, args, locals, span)
}
- _ => return Err(MirEvalError::TypeError("function pointer to non function")),
+ _ => Err(MirEvalError::TypeError("function pointer to non function")),
}
- Ok(())
}
fn exec_closure(
@@ -1839,9 +1928,9 @@ impl Evaluator<'_> {
generic_args: &Substitution,
destination: Interval,
args: &[IntervalAndTy],
- locals: &Locals<'_>,
+ locals: &Locals,
span: MirSpan,
- ) -> Result<()> {
+ ) -> Result<Option<StackFrame>> {
let mir_body = self
.db
.monomorphized_mir_body_for_closure(
@@ -1859,10 +1948,16 @@ impl Evaluator<'_> {
let arg_bytes = iter::once(Ok(closure_data))
.chain(args.iter().map(|it| Ok(it.get(&self)?.to_owned())))
.collect::<Result<Vec<_>>>()?;
- let bytes = self.interpret_mir(&mir_body, arg_bytes.into_iter()).map_err(|e| {
- MirEvalError::InFunction(Either::Right(closure), Box::new(e), span, locals.body.owner)
- })?;
- destination.write_from_bytes(self, &bytes)
+ let bytes = self
+ .interpret_mir(mir_body, arg_bytes.into_iter().map(IntervalOrOwned::Owned))
+ .map_err(|e| {
+ MirEvalError::InFunction(
+ Box::new(e),
+ vec![(Either::Right(closure), span, locals.body.owner)],
+ )
+ })?;
+ destination.write_from_bytes(self, &bytes)?;
+ Ok(None)
}
fn exec_fn_def(
@@ -1871,18 +1966,34 @@ impl Evaluator<'_> {
generic_args: &Substitution,
destination: Interval,
args: &[IntervalAndTy],
- locals: &Locals<'_>,
+ locals: &Locals,
+ target_bb: Option<BasicBlockId>,
span: MirSpan,
- ) -> Result<()> {
+ ) -> Result<Option<StackFrame>> {
let def: CallableDefId = from_chalk(self.db, def);
let generic_args = generic_args.clone();
match def {
CallableDefId::FunctionId(def) => {
if let Some(_) = self.detect_fn_trait(def) {
- self.exec_fn_trait(def, args, generic_args, locals, destination, span)?;
- return Ok(());
+ return self.exec_fn_trait(
+ def,
+ args,
+ generic_args,
+ locals,
+ destination,
+ target_bb,
+ span,
+ );
}
- self.exec_fn_with_args(def, args, generic_args, locals, destination, span)?;
+ self.exec_fn_with_args(
+ def,
+ args,
+ generic_args,
+ locals,
+ destination,
+ target_bb,
+ span,
+ )
}
CallableDefId::StructId(id) => {
let (size, variant_layout, tag) =
@@ -1894,6 +2005,7 @@ impl Evaluator<'_> {
args.iter().map(|it| it.interval.into()),
)?;
destination.write_from_bytes(self, &result)?;
+ Ok(None)
}
CallableDefId::EnumVariantId(id) => {
let (size, variant_layout, tag) =
@@ -1905,9 +2017,9 @@ impl Evaluator<'_> {
args.iter().map(|it| it.interval.into()),
)?;
destination.write_from_bytes(self, &result)?;
+ Ok(None)
}
}
- Ok(())
}
fn exec_fn_with_args(
@@ -1915,10 +2027,11 @@ impl Evaluator<'_> {
def: FunctionId,
args: &[IntervalAndTy],
generic_args: Substitution,
- locals: &Locals<'_>,
+ locals: &Locals,
destination: Interval,
+ target_bb: Option<BasicBlockId>,
span: MirSpan,
- ) -> Result<()> {
+ ) -> Result<Option<StackFrame>> {
if self.detect_and_exec_special_function(
def,
args,
@@ -1927,10 +2040,9 @@ impl Evaluator<'_> {
destination,
span,
)? {
- return Ok(());
+ return Ok(None);
}
- let arg_bytes =
- args.iter().map(|it| Ok(it.get(&self)?.to_owned())).collect::<Result<Vec<_>>>()?;
+ let arg_bytes = args.iter().map(|it| IntervalOrOwned::Borrowed(it.interval));
if let Some(self_ty_idx) =
is_dyn_method(self.db, self.trait_env.clone(), def, generic_args.clone())
{
@@ -1938,8 +2050,10 @@ impl Evaluator<'_> {
// `&T`, `&mut T`, `Box<T>`, `Rc<T>`, `Arc<T>`, and `Pin<P>` where `P` is one of possible recievers,
// the vtable is exactly in the `[ptr_size..2*ptr_size]` bytes. So we can use it without branching on
// the type.
+ let first_arg = arg_bytes.clone().next().unwrap();
+ let first_arg = first_arg.get(self)?;
let ty =
- self.vtable_map.ty_of_bytes(&arg_bytes[0][self.ptr_size()..self.ptr_size() * 2])?;
+ self.vtable_map.ty_of_bytes(&first_arg[self.ptr_size()..self.ptr_size() * 2])?;
let mut args_for_target = args.to_vec();
args_for_target[0] = IntervalAndTy {
interval: args_for_target[0].interval.slice(0..self.ptr_size()),
@@ -1962,40 +2076,65 @@ impl Evaluator<'_> {
generics_for_target,
locals,
destination,
+ target_bb,
span,
);
}
let (imp, generic_args) =
- lookup_impl_method(self.db, self.trait_env.clone(), def, generic_args);
- self.exec_looked_up_function(generic_args, locals, imp, arg_bytes, span, destination)
+ self.db.lookup_impl_method(self.trait_env.clone(), def, generic_args);
+ self.exec_looked_up_function(
+ generic_args,
+ locals,
+ imp,
+ arg_bytes,
+ span,
+ destination,
+ target_bb,
+ )
}
fn exec_looked_up_function(
&mut self,
generic_args: Substitution,
- locals: &Locals<'_>,
+ locals: &Locals,
imp: FunctionId,
- arg_bytes: Vec<Vec<u8>>,
+ arg_bytes: impl Iterator<Item = IntervalOrOwned>,
span: MirSpan,
destination: Interval,
- ) -> Result<()> {
+ target_bb: Option<BasicBlockId>,
+ ) -> Result<Option<StackFrame>> {
let def = imp.into();
let mir_body = self
.db
.monomorphized_mir_body(def, generic_args, self.trait_env.clone())
.map_err(|e| {
MirEvalError::InFunction(
- Either::Left(imp),
Box::new(MirEvalError::MirLowerError(imp, e)),
- span,
- locals.body.owner,
+ vec![(Either::Left(imp), span, locals.body.owner)],
)
})?;
- let result = self.interpret_mir(&mir_body, arg_bytes.iter().cloned()).map_err(|e| {
- MirEvalError::InFunction(Either::Left(imp), Box::new(e), span, locals.body.owner)
- })?;
- destination.write_from_bytes(self, &result)?;
- Ok(())
+ Ok(if let Some(target_bb) = target_bb {
+ let (mut locals, prev_stack_ptr) =
+ self.create_locals_for_body(mir_body.clone(), Some(destination))?;
+ self.fill_locals_for_body(&mir_body, &mut locals, arg_bytes.into_iter())?;
+ let span = (span, locals.body.owner);
+ Some(StackFrame {
+ body: mir_body,
+ locals,
+ destination: Some(target_bb),
+ prev_stack_ptr,
+ span,
+ })
+ } else {
+ let result = self.interpret_mir(mir_body, arg_bytes).map_err(|e| {
+ MirEvalError::InFunction(
+ Box::new(e),
+ vec![(Either::Left(imp), span, locals.body.owner)],
+ )
+ })?;
+ destination.write_from_bytes(self, &result)?;
+ None
+ })
}
fn exec_fn_trait(
@@ -2003,10 +2142,11 @@ impl Evaluator<'_> {
def: FunctionId,
args: &[IntervalAndTy],
generic_args: Substitution,
- locals: &Locals<'_>,
+ locals: &Locals,
destination: Interval,
+ target_bb: Option<BasicBlockId>,
span: MirSpan,
- ) -> Result<()> {
+ ) -> Result<Option<StackFrame>> {
let func = args.get(0).ok_or(MirEvalError::TypeError("fn trait with no arg"))?;
let mut func_ty = func.ty.clone();
let mut func_data = func.interval;
@@ -2023,13 +2163,28 @@ impl Evaluator<'_> {
}
match &func_ty.data(Interner).kind {
TyKind::FnDef(def, subst) => {
- self.exec_fn_def(*def, subst, destination, &args[1..], locals, span)?;
+ return self.exec_fn_def(
+ *def,
+ subst,
+ destination,
+ &args[1..],
+ locals,
+ target_bb,
+ span,
+ );
}
TyKind::Function(_) => {
- self.exec_fn_pointer(func_data, destination, &args[1..], locals, span)?;
+ return self.exec_fn_pointer(
+ func_data,
+ destination,
+ &args[1..],
+ locals,
+ target_bb,
+ span,
+ );
}
TyKind::Closure(closure, subst) => {
- self.exec_closure(
+ return self.exec_closure(
*closure,
func_data,
&Substitution::from_iter(Interner, ClosureSubst(subst).parent_subst()),
@@ -2037,7 +2192,7 @@ impl Evaluator<'_> {
&args[1..],
locals,
span,
- )?;
+ );
}
_ => {
// try to execute the manual impl of `FnTrait` for structs (nightly feature used in std)
@@ -2068,14 +2223,14 @@ impl Evaluator<'_> {
generic_args,
locals,
destination,
+ target_bb,
span,
);
}
}
- Ok(())
}
- fn eval_static(&mut self, st: StaticId, locals: &Locals<'_>) -> Result<Address> {
+ fn eval_static(&mut self, st: StaticId, locals: &Locals) -> Result<Address> {
if let Some(o) = self.static_locations.get(&st) {
return Ok(*o);
};
@@ -2123,7 +2278,7 @@ impl Evaluator<'_> {
}
}
- fn drop_place(&mut self, place: &Place, locals: &mut Locals<'_>, span: MirSpan) -> Result<()> {
+ fn drop_place(&mut self, place: &Place, locals: &mut Locals, span: MirSpan) -> Result<()> {
let (addr, ty, metadata) = self.place_addr_and_ty_and_metadata(place, locals)?;
if !locals.drop_flags.remove_place(place) {
return Ok(());
@@ -2138,7 +2293,7 @@ impl Evaluator<'_> {
fn run_drop_glue_deep(
&mut self,
ty: Ty,
- locals: &Locals<'_>,
+ locals: &Locals,
addr: Address,
_metadata: &[u8],
span: MirSpan,
@@ -2151,8 +2306,7 @@ impl Evaluator<'_> {
// we can ignore drop in them.
return Ok(());
};
- let (impl_drop_candidate, subst) = lookup_impl_method(
- self.db,
+ let (impl_drop_candidate, subst) = self.db.lookup_impl_method(
self.trait_env.clone(),
drop_fn,
Substitution::from1(Interner, ty.clone()),
@@ -2162,9 +2316,10 @@ impl Evaluator<'_> {
subst,
locals,
impl_drop_candidate,
- vec![addr.to_bytes()],
+ [IntervalOrOwned::Owned(addr.to_bytes())].into_iter(),
span,
Interval { addr: Address::Invalid(0), size: 0 },
+ None,
)?;
}
match ty.kind(Interner) {
diff --git a/crates/hir-ty/src/mir/eval/shim.rs b/crates/hir-ty/src/mir/eval/shim.rs
index ab8ecdcf17..6cdf9f03c9 100644
--- a/crates/hir-ty/src/mir/eval/shim.rs
+++ b/crates/hir-ty/src/mir/eval/shim.rs
@@ -32,7 +32,7 @@ impl Evaluator<'_> {
def: FunctionId,
args: &[IntervalAndTy],
generic_args: &Substitution,
- locals: &Locals<'_>,
+ locals: &Locals,
destination: Interval,
span: MirSpan,
) -> Result<bool> {
@@ -168,7 +168,7 @@ impl Evaluator<'_> {
fn detect_lang_function(&self, def: FunctionId) -> Option<LangItem> {
use LangItem::*;
- let candidate = lang_attr(self.db.upcast(), def)?;
+ let candidate = self.db.lang_attr(def.into())?;
// We want to execute these functions with special logic
if [PanicFmt, BeginPanic, SliceLen, DropInPlace].contains(&candidate) {
return Some(candidate);
@@ -181,7 +181,7 @@ impl Evaluator<'_> {
it: LangItem,
generic_args: &Substitution,
args: &[Vec<u8>],
- locals: &Locals<'_>,
+ locals: &Locals,
span: MirSpan,
) -> Result<Vec<u8>> {
use LangItem::*;
@@ -201,7 +201,7 @@ impl Evaluator<'_> {
not_supported!("std::fmt::format not found");
};
let hir_def::resolver::ValueNs::FunctionId(format_fn) = format_fn else { not_supported!("std::fmt::format is not a function") };
- let message_string = self.interpret_mir(&*self.db.mir_body(format_fn.into()).map_err(|e| MirEvalError::MirLowerError(format_fn, e))?, args.cloned())?;
+ let message_string = self.interpret_mir(self.db.mir_body(format_fn.into()).map_err(|e| MirEvalError::MirLowerError(format_fn, e))?, args.map(|x| IntervalOrOwned::Owned(x.clone())))?;
let addr = Address::from_bytes(&message_string[self.ptr_size()..2 * self.ptr_size()])?;
let size = from_bytes!(usize, message_string[2 * self.ptr_size()..]);
Ok(std::string::String::from_utf8_lossy(self.read_memory(addr, size)?).into_owned())
@@ -245,7 +245,7 @@ impl Evaluator<'_> {
args: &[IntervalAndTy],
_generic_args: &Substitution,
destination: Interval,
- locals: &Locals<'_>,
+ locals: &Locals,
_span: MirSpan,
) -> Result<()> {
match as_str {
@@ -353,7 +353,7 @@ impl Evaluator<'_> {
args: &[IntervalAndTy],
generic_args: &Substitution,
destination: Interval,
- locals: &Locals<'_>,
+ locals: &Locals,
span: MirSpan,
) -> Result<()> {
if let Some(name) = name.strip_prefix("simd_") {
@@ -368,7 +368,7 @@ impl Evaluator<'_> {
args: &[IntervalAndTy],
generic_args: &Substitution,
destination: Interval,
- locals: &Locals<'_>,
+ locals: &Locals,
span: MirSpan,
) -> Result<()> {
if let Some(name) = name.strip_prefix("atomic_") {
@@ -873,15 +873,17 @@ impl Evaluator<'_> {
.as_trait()
.and_then(|it| self.db.trait_data(it).method_by_name(&name![call_once]))
{
- return self.exec_fn_trait(
+ self.exec_fn_trait(
def,
&args,
// FIXME: wrong for manual impls of `FnOnce`
Substitution::empty(Interner),
locals,
destination,
+ None,
span,
- );
+ )?;
+ return Ok(());
}
}
not_supported!("FnOnce was not available for executing const_eval_select");
@@ -894,7 +896,7 @@ impl Evaluator<'_> {
&mut self,
ty: &Ty,
metadata: Interval,
- locals: &Locals<'_>,
+ locals: &Locals,
) -> Result<(usize, usize)> {
Ok(match ty.kind(Interner) {
TyKind::Str => (from_bytes!(usize, metadata.get(self)?), 1),
@@ -948,7 +950,7 @@ impl Evaluator<'_> {
args: &[IntervalAndTy],
generic_args: &Substitution,
destination: Interval,
- locals: &Locals<'_>,
+ locals: &Locals,
_span: MirSpan,
) -> Result<()> {
// We are a single threaded runtime with no UB checking and no optimization, so
diff --git a/crates/hir-ty/src/mir/eval/shim/simd.rs b/crates/hir-ty/src/mir/eval/shim/simd.rs
index 4c2e56fe2b..64fd130182 100644
--- a/crates/hir-ty/src/mir/eval/shim/simd.rs
+++ b/crates/hir-ty/src/mir/eval/shim/simd.rs
@@ -50,7 +50,7 @@ impl Evaluator<'_> {
args: &[IntervalAndTy],
_generic_args: &Substitution,
destination: Interval,
- _locals: &Locals<'_>,
+ _locals: &Locals,
_span: MirSpan,
) -> Result<()> {
match name {
diff --git a/crates/hir-ty/src/mir/eval/tests.rs b/crates/hir-ty/src/mir/eval/tests.rs
index ca4268b8fb..1129eaa549 100644
--- a/crates/hir-ty/src/mir/eval/tests.rs
+++ b/crates/hir-ty/src/mir/eval/tests.rs
@@ -30,7 +30,7 @@ fn eval_main(db: &TestDB, file_id: FileId) -> Result<(String, String), MirEvalEr
db.trait_environment(func_id.into()),
)
.map_err(|e| MirEvalError::MirLowerError(func_id.into(), e))?;
- let (result, stdout, stderr) = interpret_mir(db, &body, false);
+ let (result, stdout, stderr) = interpret_mir(db, body, false);
result?;
Ok((stdout, stderr))
}
diff --git a/crates/hir-ty/src/mir/lower/as_place.rs b/crates/hir-ty/src/mir/lower/as_place.rs
index d58777e2b6..213f151ab6 100644
--- a/crates/hir-ty/src/mir/lower/as_place.rs
+++ b/crates/hir-ty/src/mir/lower/as_place.rs
@@ -1,7 +1,7 @@
//! MIR lowering for places
use super::*;
-use hir_def::{lang_item::lang_attr, FunctionId};
+use hir_def::FunctionId;
use hir_expand::name;
macro_rules! not_supported {
@@ -162,7 +162,7 @@ impl MirLowerCtx<'_> {
let is_builtin = match self.expr_ty_without_adjust(*expr).kind(Interner) {
TyKind::Ref(..) | TyKind::Raw(..) => true,
TyKind::Adt(id, _) => {
- if let Some(lang_item) = lang_attr(self.db.upcast(), id.0) {
+ if let Some(lang_item) = self.db.lang_attr(id.0.into()) {
lang_item == LangItem::OwnedBox
} else {
false
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 4eaf99b0b8..337cfbfb62 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -1986,7 +1986,7 @@ impl Function {
return r;
}
};
- let (result, stdout, stderr) = interpret_mir(db, &body, false);
+ let (result, stdout, stderr) = interpret_mir(db, body, false);
let mut text = match result {
Ok(_) => "pass".to_string(),
Err(e) => {
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index ecb1b306a6..3499daf114 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -832,7 +832,7 @@ impl SourceAnalyzer {
None => return func,
};
let env = db.trait_environment_for_body(owner);
- method_resolution::lookup_impl_method(db, env, func, substs).0
+ db.lookup_impl_method(env, func, substs).0
}
fn resolve_impl_const_or_trait_def(