Intern projections in mir place

This commit is contained in:
hkalbasi 2023-09-08 12:39:41 +03:30
parent e4c469321c
commit 9708a29e57
7 changed files with 253 additions and 157 deletions

View File

@ -1,6 +1,6 @@
//! MIR definitions and implementation //! MIR definitions and implementation
use std::{fmt::Display, iter}; use std::{collections::hash_map::Entry, fmt::Display, iter};
use crate::{ use crate::{
consteval::usize_const, consteval::usize_const,
@ -37,6 +37,7 @@ pub use monomorphization::{
monomorphize_mir_body_bad, monomorphized_mir_body_for_closure_query, monomorphize_mir_body_bad, monomorphized_mir_body_for_closure_query,
monomorphized_mir_body_query, monomorphized_mir_body_recover, monomorphized_mir_body_query, monomorphized_mir_body_recover,
}; };
use rustc_hash::FxHashMap;
use smallvec::{smallvec, SmallVec}; use smallvec::{smallvec, SmallVec};
use stdx::{impl_from, never}; use stdx::{impl_from, never};
use triomphe::Arc; use triomphe::Arc;
@ -223,35 +224,93 @@ impl<V, T> ProjectionElem<V, T> {
type PlaceElem = ProjectionElem<LocalId, Ty>; type PlaceElem = ProjectionElem<LocalId, Ty>;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ProjectionId(u32);
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ProjectionStore {
id_to_proj: FxHashMap<ProjectionId, Box<[PlaceElem]>>,
proj_to_id: FxHashMap<Box<[PlaceElem]>, ProjectionId>,
}
impl Default for ProjectionStore {
fn default() -> Self {
let mut this = Self { id_to_proj: Default::default(), proj_to_id: Default::default() };
// Ensure that [] will get the id 0 which is used in `ProjectionId::Empty`
this.intern(Box::new([]));
this
}
}
impl ProjectionStore {
fn shrink_to_fit(&mut self) {
self.id_to_proj.shrink_to_fit();
self.proj_to_id.shrink_to_fit();
}
fn intern_if_exist(&self, projection: &[PlaceElem]) -> Option<ProjectionId> {
self.proj_to_id.get(projection).copied()
}
fn intern(&mut self, projection: Box<[PlaceElem]>) -> ProjectionId {
let new_id = ProjectionId(self.proj_to_id.len() as u32);
match self.proj_to_id.entry(projection) {
Entry::Occupied(id) => *id.get(),
Entry::Vacant(e) => {
let key_clone = e.key().clone();
e.insert(new_id);
self.id_to_proj.insert(new_id, key_clone);
new_id
}
}
}
}
impl ProjectionId {
const EMPTY: ProjectionId = ProjectionId(0);
fn lookup(self, store: &ProjectionStore) -> &[PlaceElem] {
store.id_to_proj.get(&self).unwrap()
}
fn project(self, projection: PlaceElem, store: &mut ProjectionStore) -> ProjectionId {
let mut current = self.lookup(store).to_vec();
current.push(projection);
store.intern(current.into())
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Place { pub struct Place {
pub local: LocalId, pub local: LocalId,
pub projection: Box<[PlaceElem]>, pub projection: ProjectionId,
} }
impl Place { impl Place {
fn is_parent(&self, child: &Place) -> bool { fn is_parent(&self, child: &Place, store: &ProjectionStore) -> bool {
self.local == child.local && child.projection.starts_with(&self.projection) self.local == child.local
&& child.projection.lookup(store).starts_with(&self.projection.lookup(store))
} }
/// The place itself is not included /// The place itself is not included
fn iterate_over_parents(&self) -> impl Iterator<Item = Place> + '_ { fn iterate_over_parents<'a>(
(0..self.projection.len()) &'a self,
.map(|x| &self.projection[0..x]) store: &'a ProjectionStore,
.map(|x| Place { local: self.local, projection: x.to_vec().into() }) ) -> impl Iterator<Item = Place> + 'a {
let projection = self.projection.lookup(store);
(0..projection.len()).map(|x| &projection[0..x]).filter_map(move |x| {
Some(Place { local: self.local, projection: store.intern_if_exist(x)? })
})
} }
fn project(&self, projection: PlaceElem) -> Place { fn project(&self, projection: PlaceElem, store: &mut ProjectionStore) -> Place {
Place { Place { local: self.local, projection: self.projection.project(projection, store) }
local: self.local,
projection: self.projection.iter().cloned().chain([projection]).collect(),
}
} }
} }
impl From<LocalId> for Place { impl From<LocalId> for Place {
fn from(local: LocalId) -> Self { fn from(local: LocalId) -> Self {
Self { local, projection: vec![].into() } Self { local, projection: ProjectionId::EMPTY }
} }
} }
@ -997,6 +1056,7 @@ pub struct BasicBlock {
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct MirBody { pub struct MirBody {
pub projection_store: ProjectionStore,
pub basic_blocks: Arena<BasicBlock>, pub basic_blocks: Arena<BasicBlock>,
pub locals: Arena<Local>, pub locals: Arena<Local>,
pub start_block: BasicBlockId, pub start_block: BasicBlockId,
@ -1009,11 +1069,15 @@ pub struct MirBody {
} }
impl MirBody { impl MirBody {
fn walk_places(&mut self, mut f: impl FnMut(&mut Place)) { fn walk_places(&mut self, mut f: impl FnMut(&mut Place, &mut ProjectionStore)) {
fn for_operand(op: &mut Operand, f: &mut impl FnMut(&mut Place)) { fn for_operand(
op: &mut Operand,
f: &mut impl FnMut(&mut Place, &mut ProjectionStore),
store: &mut ProjectionStore,
) {
match op { match op {
Operand::Copy(p) | Operand::Move(p) => { Operand::Copy(p) | Operand::Move(p) => {
f(p); f(p, store);
} }
Operand::Constant(_) | Operand::Static(_) => (), Operand::Constant(_) | Operand::Static(_) => (),
} }
@ -1022,30 +1086,30 @@ impl MirBody {
for statement in &mut block.statements { for statement in &mut block.statements {
match &mut statement.kind { match &mut statement.kind {
StatementKind::Assign(p, r) => { StatementKind::Assign(p, r) => {
f(p); f(p, &mut self.projection_store);
match r { match r {
Rvalue::ShallowInitBoxWithAlloc(_) => (), Rvalue::ShallowInitBoxWithAlloc(_) => (),
Rvalue::ShallowInitBox(o, _) Rvalue::ShallowInitBox(o, _)
| Rvalue::UnaryOp(_, o) | Rvalue::UnaryOp(_, o)
| Rvalue::Cast(_, o, _) | Rvalue::Cast(_, o, _)
| Rvalue::Repeat(o, _) | Rvalue::Repeat(o, _)
| Rvalue::Use(o) => for_operand(o, &mut f), | Rvalue::Use(o) => for_operand(o, &mut f, &mut self.projection_store),
Rvalue::CopyForDeref(p) Rvalue::CopyForDeref(p)
| Rvalue::Discriminant(p) | Rvalue::Discriminant(p)
| Rvalue::Len(p) | Rvalue::Len(p)
| Rvalue::Ref(_, p) => f(p), | Rvalue::Ref(_, p) => f(p, &mut self.projection_store),
Rvalue::CheckedBinaryOp(_, o1, o2) => { Rvalue::CheckedBinaryOp(_, o1, o2) => {
for_operand(o1, &mut f); for_operand(o1, &mut f, &mut self.projection_store);
for_operand(o2, &mut f); for_operand(o2, &mut f, &mut self.projection_store);
} }
Rvalue::Aggregate(_, ops) => { Rvalue::Aggregate(_, ops) => {
for op in ops.iter_mut() { for op in ops.iter_mut() {
for_operand(op, &mut f); for_operand(op, &mut f, &mut self.projection_store);
} }
} }
} }
} }
StatementKind::Deinit(p) => f(p), StatementKind::Deinit(p) => f(p, &mut self.projection_store),
StatementKind::StorageLive(_) StatementKind::StorageLive(_)
| StatementKind::StorageDead(_) | StatementKind::StorageDead(_)
| StatementKind::Nop => (), | StatementKind::Nop => (),
@ -1053,7 +1117,9 @@ impl MirBody {
} }
match &mut block.terminator { match &mut block.terminator {
Some(x) => match &mut x.kind { Some(x) => match &mut x.kind {
TerminatorKind::SwitchInt { discr, .. } => for_operand(discr, &mut f), TerminatorKind::SwitchInt { discr, .. } => {
for_operand(discr, &mut f, &mut self.projection_store)
}
TerminatorKind::FalseEdge { .. } TerminatorKind::FalseEdge { .. }
| TerminatorKind::FalseUnwind { .. } | TerminatorKind::FalseUnwind { .. }
| TerminatorKind::Goto { .. } | TerminatorKind::Goto { .. }
@ -1063,23 +1129,24 @@ impl MirBody {
| TerminatorKind::Return | TerminatorKind::Return
| TerminatorKind::Unreachable => (), | TerminatorKind::Unreachable => (),
TerminatorKind::Drop { place, .. } => { TerminatorKind::Drop { place, .. } => {
f(place); f(place, &mut self.projection_store);
} }
TerminatorKind::DropAndReplace { place, value, .. } => { TerminatorKind::DropAndReplace { place, value, .. } => {
f(place); f(place, &mut self.projection_store);
for_operand(value, &mut f); for_operand(value, &mut f, &mut self.projection_store);
} }
TerminatorKind::Call { func, args, destination, .. } => { TerminatorKind::Call { func, args, destination, .. } => {
for_operand(func, &mut f); for_operand(func, &mut f, &mut self.projection_store);
args.iter_mut().for_each(|x| for_operand(x, &mut f)); args.iter_mut()
f(destination); .for_each(|x| for_operand(x, &mut f, &mut self.projection_store));
f(destination, &mut self.projection_store);
} }
TerminatorKind::Assert { cond, .. } => { TerminatorKind::Assert { cond, .. } => {
for_operand(cond, &mut f); for_operand(cond, &mut f, &mut self.projection_store);
} }
TerminatorKind::Yield { value, resume_arg, .. } => { TerminatorKind::Yield { value, resume_arg, .. } => {
for_operand(value, &mut f); for_operand(value, &mut f, &mut self.projection_store);
f(resume_arg); f(resume_arg, &mut self.projection_store);
} }
}, },
None => (), None => (),
@ -1096,7 +1163,9 @@ impl MirBody {
binding_locals, binding_locals,
param_locals, param_locals,
closures, closures,
projection_store,
} = self; } = self;
projection_store.shrink_to_fit();
basic_blocks.shrink_to_fit(); basic_blocks.shrink_to_fit();
locals.shrink_to_fit(); locals.shrink_to_fit();
binding_locals.shrink_to_fit(); binding_locals.shrink_to_fit();

View File

@ -88,7 +88,7 @@ fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec<MovedOutOfRef>
Operand::Copy(p) | Operand::Move(p) => { Operand::Copy(p) | Operand::Move(p) => {
let mut ty: Ty = body.locals[p.local].ty.clone(); let mut ty: Ty = body.locals[p.local].ty.clone();
let mut is_dereference_of_ref = false; let mut is_dereference_of_ref = false;
for proj in &*p.projection { for proj in p.projection.lookup(&body.projection_store) {
if *proj == ProjectionElem::Deref && ty.as_reference().is_some() { if *proj == ProjectionElem::Deref && ty.as_reference().is_some() {
is_dereference_of_ref = true; is_dereference_of_ref = true;
} }
@ -195,7 +195,7 @@ enum ProjectionCase {
fn place_case(db: &dyn HirDatabase, body: &MirBody, lvalue: &Place) -> ProjectionCase { fn place_case(db: &dyn HirDatabase, body: &MirBody, lvalue: &Place) -> ProjectionCase {
let mut is_part_of = false; let mut is_part_of = false;
let mut ty = body.locals[lvalue.local].ty.clone(); let mut ty = body.locals[lvalue.local].ty.clone();
for proj in lvalue.projection.iter() { for proj in lvalue.projection.lookup(&body.projection_store).iter() {
match proj { match proj {
ProjectionElem::Deref if ty.as_adt().is_none() => return ProjectionCase::Indirect, // It's indirect in case of reference and raw ProjectionElem::Deref if ty.as_adt().is_none() => return ProjectionCase::Indirect, // It's indirect in case of reference and raw
ProjectionElem::Deref // It's direct in case of `Box<T>` ProjectionElem::Deref // It's direct in case of `Box<T>`
@ -254,7 +254,7 @@ fn ever_initialized_map(
for statement in &block.statements { for statement in &block.statements {
match &statement.kind { match &statement.kind {
StatementKind::Assign(p, _) => { StatementKind::Assign(p, _) => {
if p.projection.len() == 0 && p.local == l { if p.projection.lookup(&body.projection_store).len() == 0 && p.local == l {
is_ever_initialized = true; is_ever_initialized = true;
} }
} }
@ -289,7 +289,9 @@ fn ever_initialized_map(
| TerminatorKind::Return | TerminatorKind::Return
| TerminatorKind::Unreachable => (), | TerminatorKind::Unreachable => (),
TerminatorKind::Call { target, cleanup, destination, .. } => { TerminatorKind::Call { target, cleanup, destination, .. } => {
if destination.projection.len() == 0 && destination.local == l { if destination.projection.lookup(&body.projection_store).len() == 0
&& destination.local == l
{
is_ever_initialized = true; is_ever_initialized = true;
} }
target target
@ -389,7 +391,7 @@ fn mutability_of_locals(
| TerminatorKind::Assert { .. } | TerminatorKind::Assert { .. }
| TerminatorKind::Yield { .. } => (), | TerminatorKind::Yield { .. } => (),
TerminatorKind::Call { destination, .. } => { TerminatorKind::Call { destination, .. } => {
if destination.projection.len() == 0 { if destination.projection.lookup(&body.projection_store).len() == 0 {
if ever_init_map.get(destination.local).copied().unwrap_or_default() { if ever_init_map.get(destination.local).copied().unwrap_or_default() {
push_mut_span(destination.local, MirSpan::Unknown); push_mut_span(destination.local, MirSpan::Unknown);
} else { } else {

View File

@ -46,8 +46,8 @@ use crate::{
use super::{ use super::{
return_slot, AggregateKind, BasicBlockId, BinOp, CastKind, LocalId, MirBody, MirLowerError, return_slot, AggregateKind, BasicBlockId, BinOp, CastKind, LocalId, MirBody, MirLowerError,
MirSpan, Operand, Place, PlaceElem, ProjectionElem, Rvalue, StatementKind, TerminatorKind, MirSpan, Operand, Place, PlaceElem, ProjectionElem, ProjectionStore, Rvalue, StatementKind,
UnOp, TerminatorKind, UnOp,
}; };
mod shim; mod shim;
@ -485,17 +485,18 @@ struct DropFlags {
} }
impl DropFlags { impl DropFlags {
fn add_place(&mut self, p: Place) { fn add_place(&mut self, p: Place, store: &ProjectionStore) {
if p.iterate_over_parents().any(|it| self.need_drop.contains(&it)) { if p.iterate_over_parents(store).any(|it| self.need_drop.contains(&it)) {
return; return;
} }
self.need_drop.retain(|it| !p.is_parent(it)); self.need_drop.retain(|it| !p.is_parent(it, store));
self.need_drop.insert(p); self.need_drop.insert(p);
} }
fn remove_place(&mut self, p: &Place) -> bool { fn remove_place(&mut self, p: &Place, store: &ProjectionStore) -> bool {
// FIXME: replace parents with parts // FIXME: replace parents with parts
if let Some(parent) = p.iterate_over_parents().find(|it| self.need_drop.contains(&it)) { if let Some(parent) = p.iterate_over_parents(store).find(|it| self.need_drop.contains(&it))
{
self.need_drop.remove(&parent); self.need_drop.remove(&parent);
return true; return true;
} }
@ -656,7 +657,7 @@ impl Evaluator<'_> {
let mut addr = locals.ptr[p.local].addr; let mut addr = locals.ptr[p.local].addr;
let mut ty: Ty = locals.body.locals[p.local].ty.clone(); let mut ty: Ty = locals.body.locals[p.local].ty.clone();
let mut metadata: Option<IntervalOrOwned> = None; // locals are always sized let mut metadata: Option<IntervalOrOwned> = None; // locals are always sized
for proj in &*p.projection { for proj in p.projection.lookup(&locals.body.projection_store) {
let prev_ty = ty.clone(); let prev_ty = ty.clone();
ty = self.projected_ty(ty, proj.clone()); ty = self.projected_ty(ty, proj.clone());
match proj { match proj {
@ -837,7 +838,9 @@ impl Evaluator<'_> {
let addr = self.place_addr(l, &locals)?; let addr = self.place_addr(l, &locals)?;
let result = self.eval_rvalue(r, &mut locals)?.to_vec(&self)?; let result = self.eval_rvalue(r, &mut locals)?.to_vec(&self)?;
self.write_memory(addr, &result)?; self.write_memory(addr, &result)?;
locals.drop_flags.add_place(l.clone()); locals
.drop_flags
.add_place(l.clone(), &locals.body.projection_store);
} }
StatementKind::Deinit(_) => not_supported!("de-init statement"), StatementKind::Deinit(_) => not_supported!("de-init statement"),
StatementKind::StorageLive(_) StatementKind::StorageLive(_)
@ -889,7 +892,9 @@ impl Evaluator<'_> {
)?, )?,
it => not_supported!("unknown function type {it:?}"), it => not_supported!("unknown function type {it:?}"),
}; };
locals.drop_flags.add_place(destination.clone()); locals
.drop_flags
.add_place(destination.clone(), &locals.body.projection_store);
if let Some(stack_frame) = stack_frame { if let Some(stack_frame) = stack_frame {
self.code_stack.push(my_stack_frame); self.code_stack.push(my_stack_frame);
current_block_idx = stack_frame.locals.body.start_block; current_block_idx = stack_frame.locals.body.start_block;
@ -970,7 +975,7 @@ impl Evaluator<'_> {
) -> Result<()> { ) -> Result<()> {
let mut remain_args = body.param_locals.len(); let mut remain_args = body.param_locals.len();
for ((l, interval), value) in locals.ptr.iter().skip(1).zip(args) { for ((l, interval), value) in locals.ptr.iter().skip(1).zip(args) {
locals.drop_flags.add_place(l.into()); locals.drop_flags.add_place(l.into(), &locals.body.projection_store);
match value { match value {
IntervalOrOwned::Owned(value) => interval.write_from_bytes(self, &value)?, IntervalOrOwned::Owned(value) => interval.write_from_bytes(self, &value)?,
IntervalOrOwned::Borrowed(value) => interval.write_from_interval(self, value)?, IntervalOrOwned::Borrowed(value) => interval.write_from_interval(self, value)?,
@ -1646,7 +1651,7 @@ impl Evaluator<'_> {
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 { Ok(match it {
Operand::Copy(p) | Operand::Move(p) => { Operand::Copy(p) | Operand::Move(p) => {
locals.drop_flags.remove_place(p); locals.drop_flags.remove_place(p, &locals.body.projection_store);
self.eval_place(p, locals)? self.eval_place(p, locals)?
} }
Operand::Static(st) => { Operand::Static(st) => {
@ -2468,7 +2473,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)?; let (addr, ty, metadata) = self.place_addr_and_ty_and_metadata(place, locals)?;
if !locals.drop_flags.remove_place(place) { if !locals.drop_flags.remove_place(place, &locals.body.projection_store) {
return Ok(()); return Ok(());
} }
let metadata = match metadata { let metadata = match metadata {

View File

@ -244,6 +244,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
let locals = Arena::new(); let locals = Arena::new();
let binding_locals: ArenaMap<BindingId, LocalId> = ArenaMap::new(); let binding_locals: ArenaMap<BindingId, LocalId> = ArenaMap::new();
let mir = MirBody { let mir = MirBody {
projection_store: ProjectionStore::default(),
basic_blocks, basic_blocks,
locals, locals,
start_block, start_block,
@ -809,10 +810,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
current = c; current = c;
operands[u32::from(field_id.into_raw()) as usize] = Some(op); operands[u32::from(field_id.into_raw()) as usize] = Some(op);
} }
self.push_assignment( let rvalue = Rvalue::Aggregate(
current,
place,
Rvalue::Aggregate(
AggregateKind::Adt(variant_id, subst), AggregateKind::Adt(variant_id, subst),
match spread_place { match spread_place {
Some(sp) => operands Some(sp) => operands
@ -821,13 +819,15 @@ impl<'ctx> MirLowerCtx<'ctx> {
.map(|(i, it)| match it { .map(|(i, it)| match it {
Some(it) => it, Some(it) => it,
None => { None => {
let p = let p = sp.project(
sp.project(ProjectionElem::Field(FieldId { ProjectionElem::Field(FieldId {
parent: variant_id, parent: variant_id,
local_id: LocalFieldId::from_raw( local_id: LocalFieldId::from_raw(RawIdx::from(
RawIdx::from(i as u32), i as u32,
), )),
})); }),
&mut self.result.projection_store,
);
Operand::Copy(p) Operand::Copy(p)
} }
}) })
@ -836,9 +836,8 @@ impl<'ctx> MirLowerCtx<'ctx> {
MirLowerError::TypeError("missing field in record literal"), MirLowerError::TypeError("missing field in record literal"),
)?, )?,
}, },
),
expr_id.into(),
); );
self.push_assignment(current, place, rvalue, expr_id.into());
Ok(Some(current)) Ok(Some(current))
} }
VariantId::UnionId(union_id) => { VariantId::UnionId(union_id) => {
@ -847,10 +846,10 @@ impl<'ctx> MirLowerCtx<'ctx> {
}; };
let local_id = let local_id =
variant_data.field(name).ok_or(MirLowerError::UnresolvedField)?; variant_data.field(name).ok_or(MirLowerError::UnresolvedField)?;
let place = place.project(PlaceElem::Field(FieldId { let place = place.project(
parent: union_id.into(), PlaceElem::Field(FieldId { parent: union_id.into(), local_id }),
local_id, &mut self.result.projection_store,
})); );
self.lower_expr_to_place(*expr, place, current) self.lower_expr_to_place(*expr, place, current)
} }
} }
@ -904,7 +903,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
else { else {
return Ok(None); return Ok(None);
}; };
let p = place.project(ProjectionElem::Deref); let p = place.project(ProjectionElem::Deref, &mut self.result.projection_store);
self.push_assignment(current, p, operand.into(), expr_id.into()); self.push_assignment(current, p, operand.into(), expr_id.into());
Ok(Some(current)) Ok(Some(current))
} }
@ -1126,7 +1125,8 @@ impl<'ctx> MirLowerCtx<'ctx> {
for capture in captures.iter() { for capture in captures.iter() {
let p = Place { let p = Place {
local: self.binding_local(capture.place.local)?, local: self.binding_local(capture.place.local)?,
projection: capture projection: self.result.projection_store.intern(
capture
.place .place
.projections .projections
.clone() .clone()
@ -1143,10 +1143,13 @@ impl<'ctx> MirLowerCtx<'ctx> {
ProjectionElem::Subslice { from, to } => { ProjectionElem::Subslice { from, to } => {
ProjectionElem::Subslice { from, to } ProjectionElem::Subslice { from, to }
} }
ProjectionElem::OpaqueCast(it) => ProjectionElem::OpaqueCast(it), ProjectionElem::OpaqueCast(it) => {
ProjectionElem::OpaqueCast(it)
}
ProjectionElem::Index(it) => match it {}, ProjectionElem::Index(it) => match it {},
}) })
.collect(), .collect(),
),
}; };
match &capture.kind { match &capture.kind {
CaptureKind::ByRef(bk) => { CaptureKind::ByRef(bk) => {
@ -1261,12 +1264,11 @@ impl<'ctx> MirLowerCtx<'ctx> {
match &self.body.exprs[lhs] { match &self.body.exprs[lhs] {
Expr::Tuple { exprs, is_assignee_expr: _ } => { Expr::Tuple { exprs, is_assignee_expr: _ } => {
for (i, expr) in exprs.iter().enumerate() { for (i, expr) in exprs.iter().enumerate() {
let Some(c) = self.lower_destructing_assignment( let rhs = rhs.project(
current, ProjectionElem::TupleOrClosureField(i),
*expr, &mut self.result.projection_store,
rhs.project(ProjectionElem::TupleOrClosureField(i)), );
span, let Some(c) = self.lower_destructing_assignment(current, *expr, rhs, span)?
)?
else { else {
return Ok(None); return Ok(None);
}; };
@ -1323,17 +1325,21 @@ impl<'ctx> MirLowerCtx<'ctx> {
placeholder_subst placeholder_subst
} }
fn push_field_projection(&self, place: &mut Place, expr_id: ExprId) -> Result<()> { fn push_field_projection(&mut self, place: &mut Place, expr_id: ExprId) -> Result<()> {
if let Expr::Field { expr, name } = &self.body[expr_id] { if let Expr::Field { expr, name } = &self.body[expr_id] {
if let TyKind::Tuple(..) = self.expr_ty_after_adjustments(*expr).kind(Interner) { if let TyKind::Tuple(..) = self.expr_ty_after_adjustments(*expr).kind(Interner) {
let index = name let index = name
.as_tuple_index() .as_tuple_index()
.ok_or(MirLowerError::TypeError("named field on tuple"))?; .ok_or(MirLowerError::TypeError("named field on tuple"))?;
*place = place.project(ProjectionElem::TupleOrClosureField(index)) *place = place.project(
ProjectionElem::TupleOrClosureField(index),
&mut self.result.projection_store,
)
} else { } else {
let field = let field =
self.infer.field_resolution(expr_id).ok_or(MirLowerError::UnresolvedField)?; self.infer.field_resolution(expr_id).ok_or(MirLowerError::UnresolvedField)?;
*place = place.project(ProjectionElem::Field(field)); *place =
place.project(ProjectionElem::Field(field), &mut self.result.projection_store);
} }
} else { } else {
not_supported!("") not_supported!("")
@ -1995,13 +2001,14 @@ pub fn mir_body_for_closure_query(
FnTrait::FnOnce => vec![], FnTrait::FnOnce => vec![],
FnTrait::FnMut | FnTrait::Fn => vec![ProjectionElem::Deref], FnTrait::FnMut | FnTrait::Fn => vec![ProjectionElem::Deref],
}; };
ctx.result.walk_places(|p| { ctx.result.walk_places(|p, store| {
if let Some(it) = upvar_map.get(&p.local) { if let Some(it) = upvar_map.get(&p.local) {
let r = it.iter().find(|it| { let r = it.iter().find(|it| {
if p.projection.len() < it.0.place.projections.len() { if p.projection.lookup(&store).len() < it.0.place.projections.len() {
return false; return false;
} }
for (it, y) in p.projection.iter().zip(it.0.place.projections.iter()) { for (it, y) in p.projection.lookup(&store).iter().zip(it.0.place.projections.iter())
{
match (it, y) { match (it, y) {
(ProjectionElem::Deref, ProjectionElem::Deref) => (), (ProjectionElem::Deref, ProjectionElem::Deref) => (),
(ProjectionElem::Field(it), ProjectionElem::Field(y)) if it == y => (), (ProjectionElem::Field(it), ProjectionElem::Field(y)) if it == y => (),
@ -2019,13 +2026,18 @@ pub fn mir_body_for_closure_query(
p.local = closure_local; p.local = closure_local;
let mut next_projs = closure_projection.clone(); let mut next_projs = closure_projection.clone();
next_projs.push(PlaceElem::TupleOrClosureField(it.1)); next_projs.push(PlaceElem::TupleOrClosureField(it.1));
let prev_projs = mem::take(&mut p.projection); let prev_projs = p.projection;
if it.0.kind != CaptureKind::ByValue { if it.0.kind != CaptureKind::ByValue {
next_projs.push(ProjectionElem::Deref); next_projs.push(ProjectionElem::Deref);
} }
next_projs next_projs.extend(
.extend(prev_projs.iter().cloned().skip(it.0.place.projections.len())); prev_projs
p.projection = next_projs.into(); .lookup(&store)
.iter()
.cloned()
.skip(it.0.place.projections.len()),
);
p.projection = store.intern(next_projs.into());
} }
None => err = Some(p.clone()), None => err = Some(p.clone()),
} }

View File

@ -70,7 +70,7 @@ impl MirLowerCtx<'_> {
else { else {
return Ok(None); return Ok(None);
}; };
it.0 = it.0.project(ProjectionElem::Deref); it.0 = it.0.project(ProjectionElem::Deref, &mut self.result.projection_store);
Ok(Some(it)) Ok(Some(it))
} }
Adjust::Deref(Some(od)) => { Adjust::Deref(Some(od)) => {
@ -152,7 +152,10 @@ impl MirLowerCtx<'_> {
Operand::Static(s).into(), Operand::Static(s).into(),
expr_id.into(), expr_id.into(),
); );
Ok(Some((temp.project(ProjectionElem::Deref), current))) Ok(Some((
temp.project(ProjectionElem::Deref, &mut self.result.projection_store),
current,
)))
} }
_ => try_rvalue(self), _ => try_rvalue(self),
} }
@ -203,7 +206,7 @@ impl MirLowerCtx<'_> {
else { else {
return Ok(None); return Ok(None);
}; };
r = r.project(ProjectionElem::Deref); r = r.project(ProjectionElem::Deref, &mut self.result.projection_store);
Ok(Some((r, current))) Ok(Some((r, current)))
} }
_ => try_rvalue(self), _ => try_rvalue(self),
@ -267,7 +270,8 @@ impl MirLowerCtx<'_> {
else { else {
return Ok(None); return Ok(None);
}; };
p_base = p_base.project(ProjectionElem::Index(l_index)); p_base = p_base
.project(ProjectionElem::Index(l_index), &mut self.result.projection_store);
Ok(Some((p_base, current))) Ok(Some((p_base, current)))
} }
_ => try_rvalue(self), _ => try_rvalue(self),
@ -308,7 +312,7 @@ impl MirLowerCtx<'_> {
else { else {
return Ok(None); return Ok(None);
}; };
result = result.project(ProjectionElem::Deref); result = result.project(ProjectionElem::Deref, &mut self.result.projection_store);
Ok(Some((result, current))) Ok(Some((result, current)))
} }
@ -363,7 +367,7 @@ impl MirLowerCtx<'_> {
else { else {
return Ok(None); return Ok(None);
}; };
result = result.project(ProjectionElem::Deref); result = result.project(ProjectionElem::Deref, &mut self.result.projection_store);
Ok(Some((result, current))) Ok(Some((result, current)))
} }
} }

View File

@ -81,13 +81,16 @@ impl MirLowerCtx<'_> {
mode: MatchingMode, mode: MatchingMode,
) -> Result<(BasicBlockId, Option<BasicBlockId>)> { ) -> Result<(BasicBlockId, Option<BasicBlockId>)> {
let cnt = self.infer.pat_adjustments.get(&pattern).map(|x| x.len()).unwrap_or_default(); let cnt = self.infer.pat_adjustments.get(&pattern).map(|x| x.len()).unwrap_or_default();
cond_place.projection = cond_place cond_place.projection = self.result.projection_store.intern(
cond_place
.projection .projection
.lookup(&self.result.projection_store)
.iter() .iter()
.cloned() .cloned()
.chain((0..cnt).map(|_| ProjectionElem::Deref)) .chain((0..cnt).map(|_| ProjectionElem::Deref))
.collect::<Vec<_>>() .collect::<Vec<_>>()
.into(); .into(),
);
Ok(match &self.body.pats[pattern] { Ok(match &self.body.pats[pattern] {
Pat::Missing => return Err(MirLowerError::IncompletePattern), Pat::Missing => return Err(MirLowerError::IncompletePattern),
Pat::Wild => (current, current_else), Pat::Wild => (current, current_else),
@ -262,20 +265,23 @@ impl MirLowerCtx<'_> {
} }
} }
for (i, &pat) in prefix.iter().enumerate() { for (i, &pat) in prefix.iter().enumerate() {
let next_place = (&mut cond_place).project(ProjectionElem::ConstantIndex { let next_place = (&mut cond_place).project(
offset: i as u64, ProjectionElem::ConstantIndex { offset: i as u64, from_end: false },
from_end: false, &mut self.result.projection_store,
}); );
(current, current_else) = (current, current_else) =
self.pattern_match_inner(current, current_else, next_place, pat, mode)?; self.pattern_match_inner(current, current_else, next_place, pat, mode)?;
} }
if let Some(slice) = slice { if let Some(slice) = slice {
if mode == MatchingMode::Bind { if mode == MatchingMode::Bind {
if let Pat::Bind { id, subpat: _ } = self.body[*slice] { if let Pat::Bind { id, subpat: _ } = self.body[*slice] {
let next_place = (&mut cond_place).project(ProjectionElem::Subslice { let next_place = (&mut cond_place).project(
ProjectionElem::Subslice {
from: prefix.len() as u64, from: prefix.len() as u64,
to: suffix.len() as u64, to: suffix.len() as u64,
}); },
&mut self.result.projection_store,
);
(current, current_else) = self.pattern_match_binding( (current, current_else) = self.pattern_match_binding(
id, id,
next_place, next_place,
@ -287,10 +293,10 @@ impl MirLowerCtx<'_> {
} }
} }
for (i, &pat) in suffix.iter().enumerate() { for (i, &pat) in suffix.iter().enumerate() {
let next_place = (&mut cond_place).project(ProjectionElem::ConstantIndex { let next_place = (&mut cond_place).project(
offset: i as u64, ProjectionElem::ConstantIndex { offset: i as u64, from_end: true },
from_end: true, &mut self.result.projection_store,
}); );
(current, current_else) = (current, current_else) =
self.pattern_match_inner(current, current_else, next_place, pat, mode)?; self.pattern_match_inner(current, current_else, next_place, pat, mode)?;
} }
@ -412,13 +418,11 @@ impl MirLowerCtx<'_> {
mode, mode,
)? )?
} }
Pat::Ref { pat, mutability: _ } => self.pattern_match_inner( Pat::Ref { pat, mutability: _ } => {
current, let cond_place =
current_else, cond_place.project(ProjectionElem::Deref, &mut self.result.projection_store);
cond_place.project(ProjectionElem::Deref), self.pattern_match_inner(current, current_else, cond_place, *pat, mode)?
*pat, }
mode,
)?,
Pat::Box { .. } => not_supported!("box pattern"), Pat::Box { .. } => not_supported!("box pattern"),
Pat::ConstBlock(_) => not_supported!("const block pattern"), Pat::ConstBlock(_) => not_supported!("const block pattern"),
}) })
@ -594,7 +598,7 @@ impl MirLowerCtx<'_> {
mode: MatchingMode, mode: MatchingMode,
) -> Result<(BasicBlockId, Option<BasicBlockId>)> { ) -> Result<(BasicBlockId, Option<BasicBlockId>)> {
for (proj, arg) in args { for (proj, arg) in args {
let cond_place = cond_place.project(proj); let cond_place = cond_place.project(proj, &mut self.result.projection_store);
(current, current_else) = (current, current_else) =
self.pattern_match_inner(current, current_else, cond_place, arg, mode)?; self.pattern_match_inner(current, current_else, cond_place, arg, mode)?;
} }

View File

@ -329,7 +329,7 @@ impl<'a> MirPrettyCtx<'a> {
} }
} }
} }
f(self, p.local, &p.projection); f(self, p.local, &p.projection.lookup(&self.body.projection_store));
} }
fn operand(&mut self, r: &Operand) { fn operand(&mut self, r: &Operand) {