Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/mir/eval.rs')
-rw-r--r--crates/hir-ty/src/mir/eval.rs183
1 files changed, 99 insertions, 84 deletions
diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs
index 87d64e567e..104b90eaf5 100644
--- a/crates/hir-ty/src/mir/eval.rs
+++ b/crates/hir-ty/src/mir/eval.rs
@@ -156,26 +156,26 @@ impl TlsData {
}
}
-struct StackFrame {
- locals: Locals,
+struct StackFrame<'a> {
+ locals: Locals<'a>,
destination: Option<BasicBlockId>,
prev_stack_ptr: usize,
span: (MirSpan, DefWithBodyId),
}
#[derive(Clone)]
-enum MirOrDynIndex {
- Mir(Arc<MirBody>),
+enum MirOrDynIndex<'a> {
+ Mir(&'a MirBody),
Dyn(usize),
}
-pub struct Evaluator<'db> {
+pub struct Evaluator<'a, 'db> {
db: &'db dyn HirDatabase,
param_env: ParamEnvAndCrate<'db>,
- target_data_layout: Arc<TargetDataLayout>,
+ target_data_layout: &'db TargetDataLayout,
stack: Vec<u8>,
heap: Vec<u8>,
- code_stack: Vec<StackFrame>,
+ code_stack: Vec<StackFrame<'a>>,
/// 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>,
@@ -190,11 +190,11 @@ pub struct Evaluator<'db> {
layout_cache: RefCell<FxHashMap<Ty<'db>, Arc<Layout>>>,
projected_ty_cache: RefCell<FxHashMap<(Ty<'db>, PlaceElem), Ty<'db>>>,
not_special_fn_cache: RefCell<FxHashSet<FunctionId>>,
- mir_or_dyn_index_cache: RefCell<FxHashMap<(FunctionId, GenericArgs<'db>), MirOrDynIndex>>,
+ mir_or_dyn_index_cache: RefCell<FxHashMap<(FunctionId, GenericArgs<'db>), MirOrDynIndex<'a>>>,
/// Constantly dropping and creating `Locals` is very costly. We store
/// old locals that we normally want to drop here, to reuse their allocations
/// later.
- unused_locals_store: RefCell<FxHashMap<DefWithBodyId, Vec<Locals>>>,
+ unused_locals_store: RefCell<FxHashMap<DefWithBodyId, Vec<Locals<'a>>>>,
cached_ptr_size: usize,
cached_fn_trait_func: Option<FunctionId>,
cached_fn_mut_trait_func: Option<FunctionId>,
@@ -237,17 +237,21 @@ impl Interval {
Self { addr, size }
}
- fn get<'a, 'db>(&self, memory: &'a Evaluator<'db>) -> Result<'db, &'a [u8]> {
+ fn get<'b, 'a, 'db: 'a>(&self, memory: &'b Evaluator<'a, 'db>) -> Result<'db, &'b [u8]> {
memory.read_memory(self.addr, self.size)
}
- fn write_from_bytes<'db>(&self, memory: &mut Evaluator<'db>, bytes: &[u8]) -> Result<'db, ()> {
+ fn write_from_bytes<'a, 'db: 'a>(
+ &self,
+ memory: &mut Evaluator<'a, 'db>,
+ bytes: &[u8],
+ ) -> Result<'db, ()> {
memory.write_memory(self.addr, bytes)
}
- fn write_from_interval<'db>(
+ fn write_from_interval<'a, 'db: 'a>(
&self,
- memory: &mut Evaluator<'db>,
+ memory: &mut Evaluator<'a, 'db>,
interval: Interval,
) -> Result<'db, ()> {
memory.copy_from_interval(self.addr, interval)
@@ -259,16 +263,22 @@ impl Interval {
}
impl<'db> IntervalAndTy<'db> {
- fn get<'a>(&self, memory: &'a Evaluator<'db>) -> Result<'db, &'a [u8]> {
+ fn get<'b, 'a>(&self, memory: &'b Evaluator<'a, 'db>) -> Result<'db, &'b [u8]>
+ where
+ 'db: 'a,
+ {
memory.read_memory(self.interval.addr, self.interval.size)
}
- fn new(
+ fn new<'a>(
addr: Address,
ty: Ty<'db>,
- evaluator: &Evaluator<'db>,
- locals: &Locals,
- ) -> Result<'db, IntervalAndTy<'db>> {
+ evaluator: &Evaluator<'a, 'db>,
+ locals: &Locals<'a>,
+ ) -> Result<'db, IntervalAndTy<'db>>
+ where
+ 'db: 'a,
+ {
let size = evaluator.size_of_sized(ty, locals, "type of interval")?;
Ok(IntervalAndTy { interval: Interval { addr, size }, ty })
}
@@ -286,7 +296,7 @@ impl From<Interval> for IntervalOrOwned {
}
impl IntervalOrOwned {
- fn get<'a, 'db>(&'a self, memory: &'a Evaluator<'db>) -> Result<'db, &'a [u8]> {
+ fn get<'b, 'a, 'db: 'a>(&'b self, memory: &'b Evaluator<'a, 'db>) -> Result<'db, &'b [u8]> {
Ok(match self {
IntervalOrOwned::Owned(o) => o,
IntervalOrOwned::Borrowed(b) => b.get(memory)?,
@@ -576,9 +586,9 @@ impl DropFlags {
}
#[derive(Debug)]
-struct Locals {
+struct Locals<'a> {
ptr: ArenaMap<LocalId, Interval>,
- body: Arc<MirBody>,
+ body: &'a MirBody,
drop_flags: DropFlags,
}
@@ -596,9 +606,9 @@ impl MirOutput {
}
}
-pub fn interpret_mir<'db>(
+pub fn interpret_mir<'a, 'db: 'a>(
db: &'db dyn HirDatabase,
- body: Arc<MirBody>,
+ body: &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
@@ -613,7 +623,7 @@ pub fn interpret_mir<'db>(
if evaluator.ptr_size() != size_of::<usize>() {
not_supported!("targets with different pointer size from host");
}
- let interval = evaluator.interpret_mir(body.clone(), None.into_iter())?;
+ let interval = evaluator.interpret_mir(body, None.into_iter())?;
let bytes = interval.get(&evaluator)?;
let mut memory_map = evaluator.create_memory_map(
bytes,
@@ -638,13 +648,13 @@ const EXECUTION_LIMIT: usize = 100_000;
#[cfg(not(test))]
const EXECUTION_LIMIT: usize = 10_000_000;
-impl<'db> Evaluator<'db> {
+impl<'a, 'db: 'a> Evaluator<'a, 'db> {
pub fn new(
db: &'db dyn HirDatabase,
owner: DefWithBodyId,
assert_placeholder_ty_is_unused: bool,
trait_env: Option<ParamEnvAndCrate<'db>>,
- ) -> Result<'db, Evaluator<'db>> {
+ ) -> Result<'db, Evaluator<'a, 'db>> {
let module = owner.module(db);
let crate_id = module.krate(db);
let target_data_layout = match db.target_data_layout(crate_id) {
@@ -705,11 +715,11 @@ impl<'db> Evaluator<'db> {
self.infcx.interner.lang_items()
}
- fn place_addr(&self, p: &Place, locals: &Locals) -> Result<'db, Address> {
+ fn place_addr(&self, p: &Place, locals: &Locals<'a>) -> Result<'db, Address> {
Ok(self.place_addr_and_ty_and_metadata(p, locals)?.0)
}
- fn place_interval(&self, p: &Place, locals: &Locals) -> Result<'db, Interval> {
+ fn place_interval(&self, p: &Place, locals: &Locals<'a>) -> Result<'db, Interval> {
let place_addr_and_ty = self.place_addr_and_ty_and_metadata(p, locals)?;
Ok(Interval {
addr: place_addr_and_ty.0,
@@ -736,10 +746,10 @@ impl<'db> Evaluator<'db> {
r
}
- fn place_addr_and_ty_and_metadata<'a>(
- &'a self,
+ fn place_addr_and_ty_and_metadata<'b>(
+ &'b self,
p: &Place,
- locals: &'a Locals,
+ locals: &'b Locals<'a>,
) -> Result<'db, (Address, Ty<'db>, Option<IntervalOrOwned>)> {
let mut addr = locals.ptr[p.local].addr;
let mut ty: Ty<'db> = locals.body.locals[p.local].ty.as_ref();
@@ -873,11 +883,11 @@ impl<'db> Evaluator<'db> {
self.layout(Ty::new_adt(self.interner(), adt, subst))
}
- fn place_ty<'a>(&'a self, p: &Place, locals: &'a Locals) -> Result<'db, Ty<'db>> {
+ fn place_ty<'b>(&'b self, p: &Place, locals: &'b Locals<'a>) -> Result<'db, Ty<'db>> {
Ok(self.place_addr_and_ty_and_metadata(p, locals)?.1)
}
- fn operand_ty(&self, o: &Operand, locals: &Locals) -> Result<'db, Ty<'db>> {
+ fn operand_ty(&self, o: &Operand, locals: &Locals<'a>) -> Result<'db, Ty<'db>> {
Ok(match &o.kind {
OperandKind::Copy(p) | OperandKind::Move(p) => self.place_ty(p, locals)?,
OperandKind::Constant { konst: _, ty } => ty.as_ref(),
@@ -898,7 +908,7 @@ impl<'db> Evaluator<'db> {
fn operand_ty_and_eval(
&mut self,
o: &Operand,
- locals: &mut Locals,
+ locals: &mut Locals<'a>,
) -> Result<'db, IntervalAndTy<'db>> {
Ok(IntervalAndTy {
interval: self.eval_operand(o, locals)?,
@@ -908,7 +918,7 @@ impl<'db> Evaluator<'db> {
fn interpret_mir(
&mut self,
- body: Arc<MirBody>,
+ body: &'a MirBody,
args: impl Iterator<Item = IntervalOrOwned>,
) -> Result<'db, Interval> {
if let Some(it) = self.stack_depth_limit.checked_sub(1) {
@@ -917,8 +927,8 @@ impl<'db> Evaluator<'db> {
return Err(MirEvalError::StackOverflow);
}
let mut current_block_idx = body.start_block;
- let (mut locals, prev_stack_ptr) = self.create_locals_for_body(&body, None)?;
- self.fill_locals_for_body(&body, &mut locals, args)?;
+ let (mut locals, prev_stack_ptr) = self.create_locals_for_body(body, 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 { locals, destination: None, prev_stack_ptr, span });
@@ -1073,7 +1083,7 @@ impl<'db> Evaluator<'db> {
fn fill_locals_for_body(
&mut self,
body: &MirBody,
- locals: &mut Locals,
+ locals: &mut Locals<'a>,
args: impl Iterator<Item = IntervalOrOwned>,
) -> Result<'db, ()> {
let mut remain_args = body.param_locals.len();
@@ -1096,19 +1106,15 @@ impl<'db> Evaluator<'db> {
fn create_locals_for_body(
&mut self,
- body: &Arc<MirBody>,
+ body: &'a MirBody,
destination: Option<Interval>,
- ) -> Result<'db, (Locals, usize)> {
+ ) -> Result<'db, (Locals<'a>, usize)> {
let mut locals =
match self.unused_locals_store.borrow_mut().entry(body.owner).or_default().pop() {
- None => Locals {
- ptr: ArenaMap::new(),
- body: body.clone(),
- drop_flags: DropFlags::default(),
- },
+ None => Locals { ptr: ArenaMap::new(), body, drop_flags: DropFlags::default() },
Some(mut l) => {
l.drop_flags.clear();
- l.body = body.clone();
+ l.body = body;
l
}
};
@@ -1145,7 +1151,7 @@ impl<'db> Evaluator<'db> {
Ok((locals, prev_stack_pointer))
}
- fn eval_rvalue(&mut self, r: &Rvalue, locals: &mut Locals) -> Result<'db, IntervalOrOwned> {
+ fn eval_rvalue(&mut self, r: &Rvalue, locals: &mut Locals<'a>) -> Result<'db, IntervalOrOwned> {
use IntervalOrOwned::*;
Ok(match r {
Rvalue::Use(it) => Borrowed(self.eval_operand(it, locals)?),
@@ -1662,7 +1668,7 @@ impl<'db> Evaluator<'db> {
Ok(r)
}
Variants::Multiple { tag, tag_encoding, variants, .. } => {
- let size = tag.size(&*self.target_data_layout).bytes_usize();
+ let size = tag.size(self.target_data_layout).bytes_usize();
let offset = layout.fields.offset(0).bytes_usize(); // The only field on enum variants is the tag field
let is_signed = tag.is_signed();
match tag_encoding {
@@ -1804,7 +1810,7 @@ impl<'db> Evaluator<'db> {
&mut self,
it: VariantId,
subst: GenericArgs<'db>,
- locals: &Locals,
+ locals: &Locals<'a>,
) -> Result<'db, (usize, Arc<Layout>, Option<(usize, usize, i128)>)> {
let adt = it.adt_id(self.db);
if let DefWithBodyId::VariantId(f) = locals.body.owner
@@ -1851,7 +1857,7 @@ impl<'db> Evaluator<'db> {
if have_tag {
Some((
layout.fields.offset(0).bytes_usize(),
- tag.size(&*self.target_data_layout).bytes_usize(),
+ tag.size(self.target_data_layout).bytes_usize(),
discriminant,
))
} else {
@@ -1898,7 +1904,7 @@ impl<'db> Evaluator<'db> {
Ok(result)
}
- fn eval_operand(&mut self, it: &Operand, locals: &mut Locals) -> Result<'db, Interval> {
+ fn eval_operand(&mut self, it: &Operand, locals: &mut Locals<'a>) -> Result<'db, Interval> {
Ok(match &it.kind {
OperandKind::Copy(p) | OperandKind::Move(p) => {
locals.drop_flags.remove_place(p, &locals.body.projection_store);
@@ -2051,7 +2057,7 @@ impl<'db> Evaluator<'db> {
#[allow(clippy::double_parens)]
fn allocate_const_in_heap(
&mut self,
- locals: &Locals,
+ locals: &Locals<'a>,
konst: Const<'db>,
) -> Result<'db, Interval> {
match konst.kind() {
@@ -2089,7 +2095,7 @@ impl<'db> Evaluator<'db> {
fn allocate_allocation_in_heap(
&mut self,
- locals: &Locals,
+ locals: &Locals<'a>,
allocation: Allocation<'db>,
) -> Result<'db, Interval> {
let AllocationData { ty, memory: ref v, ref memory_map } = *allocation;
@@ -2128,7 +2134,7 @@ impl<'db> Evaluator<'db> {
Ok(Interval::new(addr, size))
}
- fn eval_place(&mut self, p: &Place, locals: &Locals) -> Result<'db, Interval> {
+ fn eval_place(&mut self, p: &Place, locals: &Locals<'a>) -> Result<'db, Interval> {
let addr = self.place_addr(p, locals)?;
Ok(Interval::new(
addr,
@@ -2228,7 +2234,11 @@ impl<'db> Evaluator<'db> {
Ok(())
}
- fn size_align_of(&self, ty: Ty<'db>, locals: &Locals) -> Result<'db, Option<(usize, usize)>> {
+ fn size_align_of(
+ &self,
+ ty: Ty<'db>,
+ locals: &Locals<'a>,
+ ) -> Result<'db, Option<(usize, usize)>> {
if let Some(layout) = self.layout_cache.borrow().get(&ty) {
return Ok(layout
.is_sized()
@@ -2257,7 +2267,7 @@ impl<'db> Evaluator<'db> {
fn size_of_sized(
&self,
ty: Ty<'db>,
- locals: &Locals,
+ locals: &Locals<'a>,
what: &'static str,
) -> Result<'db, usize> {
match self.size_align_of(ty, locals)? {
@@ -2271,7 +2281,7 @@ impl<'db> Evaluator<'db> {
fn size_align_of_sized(
&self,
ty: Ty<'db>,
- locals: &Locals,
+ locals: &Locals<'a>,
what: &'static str,
) -> Result<'db, (usize, usize)> {
match self.size_align_of(ty, locals)? {
@@ -2312,13 +2322,13 @@ impl<'db> Evaluator<'db> {
&self,
bytes: &[u8],
ty: Ty<'db>,
- locals: &Locals,
+ locals: &Locals<'a>,
) -> Result<'db, ComplexMemoryMap<'db>> {
- fn rec<'db>(
- this: &Evaluator<'db>,
+ fn rec<'a, 'db: 'a>(
+ this: &Evaluator<'a, 'db>,
bytes: &[u8],
ty: Ty<'db>,
- locals: &Locals,
+ locals: &Locals<'a>,
mm: &mut ComplexMemoryMap<'db>,
stack_depth_limit: usize,
) -> Result<'db, ()> {
@@ -2436,7 +2446,7 @@ impl<'db> Evaluator<'db> {
if let Some((v, l)) = detect_variant_from_bytes(
&layout,
this.db,
- &this.target_data_layout,
+ this.target_data_layout,
bytes,
e,
) {
@@ -2487,7 +2497,7 @@ impl<'db> Evaluator<'db> {
ty_of_bytes: impl Fn(&[u8]) -> Result<'db, Ty<'db>> + Copy,
addr: Address,
ty: Ty<'db>,
- locals: &Locals,
+ locals: &Locals<'a>,
) -> Result<'db, ()> {
// FIXME: support indirect references
let layout = self.layout(ty)?;
@@ -2546,7 +2556,7 @@ impl<'db> Evaluator<'db> {
if let Some((ev, layout)) = detect_variant_from_bytes(
&layout,
self.db,
- &self.target_data_layout,
+ self.target_data_layout,
self.read_memory(addr, layout.size.bytes_usize())?,
e,
) {
@@ -2619,10 +2629,10 @@ impl<'db> Evaluator<'db> {
bytes: Interval,
destination: Interval,
args: &[IntervalAndTy<'db>],
- locals: &Locals,
+ locals: &Locals<'a>,
target_bb: Option<BasicBlockId>,
span: MirSpan,
- ) -> Result<'db, Option<StackFrame>> {
+ ) -> Result<'db, Option<StackFrame<'a>>> {
let id = from_bytes!(usize, bytes.get(self)?);
let next_ty = self.vtable_map.ty(id)?;
use rustc_type_ir::TyKind;
@@ -2650,9 +2660,9 @@ impl<'db> Evaluator<'db> {
generic_args: GenericArgs<'db>,
destination: Interval,
args: &[IntervalAndTy<'db>],
- locals: &Locals,
+ locals: &Locals<'a>,
span: MirSpan,
- ) -> Result<'db, Option<StackFrame>> {
+ ) -> Result<'db, Option<StackFrame<'a>>> {
let mir_body = self
.db
.monomorphized_mir_body_for_closure(
@@ -2688,10 +2698,10 @@ impl<'db> Evaluator<'db> {
generic_args: GenericArgs<'db>,
destination: Interval,
args: &[IntervalAndTy<'db>],
- locals: &Locals,
+ locals: &Locals<'a>,
target_bb: Option<BasicBlockId>,
span: MirSpan,
- ) -> Result<'db, Option<StackFrame>> {
+ ) -> Result<'db, Option<StackFrame<'a>>> {
match def {
CallableDefId::FunctionId(def) => {
if self.detect_fn_trait(def).is_some() {
@@ -2746,9 +2756,9 @@ impl<'db> Evaluator<'db> {
&self,
def: FunctionId,
generic_args: GenericArgs<'db>,
- locals: &Locals,
+ locals: &Locals<'a>,
span: MirSpan,
- ) -> Result<'db, MirOrDynIndex> {
+ ) -> Result<'db, MirOrDynIndex<'a>> {
let pair = (def, generic_args);
if let Some(r) = self.mir_or_dyn_index_cache.borrow().get(&pair) {
return Ok(r.clone());
@@ -2788,11 +2798,11 @@ impl<'db> Evaluator<'db> {
mut def: FunctionId,
args: &[IntervalAndTy<'db>],
generic_args: GenericArgs<'db>,
- locals: &Locals,
+ locals: &Locals<'a>,
destination: Interval,
target_bb: Option<BasicBlockId>,
span: MirSpan,
- ) -> Result<'db, Option<StackFrame>> {
+ ) -> Result<'db, Option<StackFrame<'a>>> {
if self.detect_and_exec_special_function(
def,
args,
@@ -2854,18 +2864,18 @@ impl<'db> Evaluator<'db> {
fn exec_looked_up_function(
&mut self,
- mir_body: Arc<MirBody>,
- locals: &Locals,
+ mir_body: &'a MirBody,
+ locals: &Locals<'a>,
def: FunctionId,
arg_bytes: impl Iterator<Item = IntervalOrOwned>,
span: MirSpan,
destination: Interval,
target_bb: Option<BasicBlockId>,
- ) -> Result<'db, Option<StackFrame>> {
+ ) -> Result<'db, Option<StackFrame<'a>>> {
Ok(if let Some(target_bb) = target_bb {
let (mut locals, prev_stack_ptr) =
- self.create_locals_for_body(&mir_body, Some(destination))?;
- self.fill_locals_for_body(&mir_body, &mut locals, arg_bytes.into_iter())?;
+ self.create_locals_for_body(mir_body, Some(destination))?;
+ self.fill_locals_for_body(mir_body, &mut locals, arg_bytes.into_iter())?;
let span = (span, locals.body.owner);
Some(StackFrame { locals, destination: Some(target_bb), prev_stack_ptr, span })
} else {
@@ -2885,11 +2895,11 @@ impl<'db> Evaluator<'db> {
def: FunctionId,
args: &[IntervalAndTy<'db>],
generic_args: GenericArgs<'db>,
- locals: &Locals,
+ locals: &Locals<'a>,
destination: Interval,
target_bb: Option<BasicBlockId>,
span: MirSpan,
- ) -> Result<'db, Option<StackFrame>> {
+ ) -> Result<'db, Option<StackFrame<'a>>> {
let func = args
.first()
.ok_or_else(|| MirEvalError::InternalError("fn trait with no arg".into()))?;
@@ -2954,7 +2964,7 @@ impl<'db> Evaluator<'db> {
}
}
- fn eval_static(&mut self, st: StaticId, locals: &Locals) -> Result<'db, Address> {
+ fn eval_static(&mut self, st: StaticId, locals: &Locals<'a>) -> Result<'db, Address> {
if let Some(o) = self.static_locations.get(&st) {
return Ok(*o);
};
@@ -3001,7 +3011,12 @@ impl<'db> Evaluator<'db> {
}
}
- fn drop_place(&mut self, place: &Place, locals: &mut Locals, span: MirSpan) -> Result<'db, ()> {
+ fn drop_place(
+ &mut self,
+ place: &Place,
+ locals: &mut Locals<'a>,
+ span: MirSpan,
+ ) -> Result<'db, ()> {
let (addr, ty, metadata) = self.place_addr_and_ty_and_metadata(place, locals)?;
if !locals.drop_flags.remove_place(place, &locals.body.projection_store) {
return Ok(());
@@ -3016,7 +3031,7 @@ impl<'db> Evaluator<'db> {
fn run_drop_glue_deep(
&mut self,
ty: Ty<'db>,
- locals: &Locals,
+ locals: &Locals<'a>,
addr: Address,
_metadata: &[u8],
span: MirSpan,