Unnamed repository; edit this file 'description' to name the repository.
Merge pull request #22474 from flodiebold/intern-mir-projections
refactor: Intern MIR projections using the new ty interning infrastructure
| -rw-r--r-- | crates/hir-ty/src/mir.rs | 190 | ||||
| -rw-r--r-- | crates/hir-ty/src/mir/borrowck.rs | 20 | ||||
| -rw-r--r-- | crates/hir-ty/src/mir/eval.rs | 38 | ||||
| -rw-r--r-- | crates/hir-ty/src/mir/lower.rs | 182 | ||||
| -rw-r--r-- | crates/hir-ty/src/mir/lower/as_place.rs | 64 | ||||
| -rw-r--r-- | crates/hir-ty/src/mir/lower/pattern_matching.rs | 125 | ||||
| -rw-r--r-- | crates/hir-ty/src/mir/pretty.rs | 2 | ||||
| -rw-r--r-- | crates/hir-ty/src/next_solver.rs | 8 | ||||
| -rw-r--r-- | crates/hir-ty/src/next_solver/interner.rs | 2 | ||||
| -rw-r--r-- | crates/ide/src/inlay_hints/implicit_drop.rs | 2 |
10 files changed, 330 insertions, 303 deletions
diff --git a/crates/hir-ty/src/mir.rs b/crates/hir-ty/src/mir.rs index 5f61b1defb..e82038907c 100644 --- a/crates/hir-ty/src/mir.rs +++ b/crates/hir-ty/src/mir.rs @@ -1,6 +1,6 @@ //! MIR definitions and implementation -use std::{collections::hash_map::Entry, fmt::Display, iter}; +use std::{fmt::Display, iter}; use base_db::Crate; use either::Either; @@ -8,10 +8,14 @@ use hir_def::{ FieldId, StaticId, TupleFieldId, UnionId, VariantId, hir::{BindingId, Expr, ExprId, Ordering, PatId}, }; +use intern::{InternedSlice, InternedSliceRef, impl_slice_internable}; use la_arena::{Arena, ArenaMap, Idx, RawIdx}; use rustc_ast_ir::Mutability; use rustc_hash::FxHashMap; -use rustc_type_ir::inherent::{GenericArgs as _, IntoKind, Ty as _}; +use rustc_type_ir::{ + CollectAndApply, GenericTypeVisitable, + inherent::{GenericArgs as _, IntoKind, Ty as _}, +}; use smallvec::{SmallVec, smallvec}; use stdx::{impl_from, never}; @@ -24,6 +28,7 @@ use crate::{ next_solver::{ Allocation, AllocationData, DbInterner, ErrorGuaranteed, GenericArgs, ParamEnv, StoredAllocation, StoredConst, StoredGenericArgs, StoredTy, Ty, TyKind, + impl_stored_interned_slice, infer::{InferCtxt, traits::ObligationCause}, obligation_ctxt::ObligationCtxt, }, @@ -145,7 +150,7 @@ impl<'db> Operand { } } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum ProjectionElem<V: PartialEq> { Deref, Field(Either<FieldId, TupleFieldId>), @@ -155,7 +160,7 @@ pub enum ProjectionElem<V: PartialEq> { ConstantIndex { offset: u64, from_end: bool }, Subslice { from: u64, to: u64 }, //Downcast(Option<Symbol>, VariantIdx), - OpaqueCast(StoredTy), + OpaqueCast(std::convert::Infallible), } impl<V: PartialEq> ProjectionElem<V> { @@ -260,97 +265,114 @@ impl<V: PartialEq> ProjectionElem<V> { type PlaceElem = ProjectionElem<LocalId>; -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct ProjectionId(u32); +impl<W: crate::next_solver::WorldExposer> GenericTypeVisitable<W> for PlaceElem { + fn generic_visit_with(&self, _: &mut W) {} +} + +impl_slice_internable!(gc; ProjectionStorage, (), PlaceElem); +impl_stored_interned_slice!(ProjectionStorage, Projection, StoredProjection); -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ProjectionStore { - id_to_proj: FxHashMap<ProjectionId, Box<[PlaceElem]>>, - proj_to_id: FxHashMap<Box<[PlaceElem]>, ProjectionId>, +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +pub struct Projection<'db> { + interned: InternedSliceRef<'db, ProjectionStorage>, } -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<'db> std::fmt::Debug for Projection<'db> { + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + (*self).as_slice().fmt(fmt) } } -impl ProjectionStore { - pub fn shrink_to_fit(&mut self) { - self.id_to_proj.shrink_to_fit(); - self.proj_to_id.shrink_to_fit(); +impl<'db> Projection<'db> { + pub fn new_from_iter<I, T>(args: I) -> T::Output + where + I: IntoIterator<Item = T>, + T: CollectAndApply<PlaceElem, Self>, + { + CollectAndApply::collect_and_apply(args.into_iter(), Self::new_from_slice) } - pub fn intern_if_exist(&self, projection: &[PlaceElem]) -> Option<ProjectionId> { - self.proj_to_id.get(projection).copied() + #[inline] + pub fn new_from_slice(slice: &[PlaceElem]) -> Self { + Self { interned: InternedSlice::from_header_and_slice((), slice) } } - pub 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 - } - } + #[inline] + pub fn as_slice(self) -> &'db [PlaceElem] { + &self.interned.get().slice + } + + pub fn project(self, projection: PlaceElem) -> Projection<'db> { + Projection::new_from_iter(self.as_slice().iter().copied().chain([projection])) } } -impl ProjectionId { - pub const EMPTY: ProjectionId = ProjectionId(0); +impl<'db> std::ops::Deref for Projection<'db> { + type Target = [PlaceElem]; - pub fn is_empty(self) -> bool { - self == ProjectionId::EMPTY + fn deref(&self) -> &Self::Target { + self.as_slice() } +} - pub fn lookup(self, store: &ProjectionStore) -> &[PlaceElem] { - store.id_to_proj.get(&self).unwrap() +impl StoredProjection { + // FIXME: rename to as_slice + pub fn lookup(&self) -> &[PlaceElem] { + self.as_ref().as_slice() } - pub fn project(self, projection: PlaceElem, store: &mut ProjectionStore) -> ProjectionId { - let mut current = self.lookup(store).to_vec(); - current.push(projection); - store.intern(current.into()) + pub fn is_empty(&self) -> bool { + self.lookup().is_empty() } } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +// FIXME: would be nicer to rename PlaceRef -> Place, Place -> StoredPlace, but I didn't want to blow up the diff +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct PlaceRef<'db> { + pub local: LocalId, + pub projection: Projection<'db>, +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Place { pub local: LocalId, - pub projection: ProjectionId, + pub projection: StoredProjection, } impl Place { - fn is_parent(&self, child: &Place, store: &ProjectionStore) -> bool { + pub fn as_ref<'db>(&self) -> PlaceRef<'db> { + PlaceRef { local: self.local, projection: self.projection.as_ref() } + } +} + +impl<'db> PlaceRef<'db> { + fn is_parent(&self, child: PlaceRef<'db>) -> bool { self.local == child.local - && child.projection.lookup(store).starts_with(self.projection.lookup(store)) + && child.projection.as_slice().starts_with(self.projection.as_slice()) } /// The place itself is not included - fn iterate_over_parents<'a>( - &'a self, - store: &'a ProjectionStore, - ) -> 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 iterate_over_parents<'a>(&'a self) -> impl Iterator<Item = PlaceRef<'db>> + 'a { + let projection = self.projection.as_slice(); + (0..projection.len()).map(move |x| PlaceRef { + local: self.local, + projection: Projection::new_from_slice(&projection[0..x]), }) } - fn project(&self, projection: PlaceElem, store: &mut ProjectionStore) -> Place { - Place { local: self.local, projection: self.projection.project(projection, store) } + fn project(&self, projection: PlaceElem) -> PlaceRef<'db> { + PlaceRef { local: self.local, projection: self.projection.project(projection) } + } + + pub fn store(&self) -> Place { + Place { local: self.local, projection: self.projection.store() } } } -impl From<LocalId> for Place { +impl<'db> From<LocalId> for PlaceRef<'db> { fn from(local: LocalId) -> Self { - Self { local, projection: ProjectionId::EMPTY } + let empty: &[PlaceElem] = &[]; + PlaceRef { local, projection: Projection::new_from_slice(empty) } } } @@ -1081,7 +1103,6 @@ pub struct BasicBlock { #[derive(Debug, Clone, PartialEq, Eq)] pub struct MirBody { - pub projection_store: ProjectionStore, pub basic_blocks: Arena<BasicBlock>, pub locals: Arena<Local>, pub start_block: BasicBlockId, @@ -1099,15 +1120,11 @@ impl MirBody { self.binding_locals.iter().map(|(it, y)| (*y, it)).collect() } - 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, &mut ProjectionStore), - store: &mut ProjectionStore, - ) { + fn walk_places(&mut self, mut f: impl FnMut(&mut Place)) { + fn for_operand(op: &mut Operand, f: &mut impl FnMut(&mut Place)) { match &mut op.kind { OperandKind::Copy(p) | OperandKind::Move(p) => { - f(p, store); + f(p); } OperandKind::Constant { .. } | OperandKind::Static(_) @@ -1118,25 +1135,25 @@ impl MirBody { for statement in &mut block.statements { match &mut statement.kind { StatementKind::Assign(p, r) => { - f(p, &mut self.projection_store); + f(p); match r { Rvalue::ShallowInitBoxWithAlloc(_) => (), Rvalue::ShallowInitBox(o, _) | Rvalue::UnaryOp(_, o) | Rvalue::Cast(_, o, _) | Rvalue::Repeat(o, _) - | Rvalue::Use(o) => for_operand(o, &mut f, &mut self.projection_store), + | Rvalue::Use(o) => for_operand(o, &mut f), Rvalue::CopyForDeref(p) | Rvalue::Discriminant(p) | Rvalue::Len(p) - | Rvalue::Ref(_, p) => f(p, &mut self.projection_store), + | Rvalue::Ref(_, p) => f(p), Rvalue::CheckedBinaryOp(_, o1, o2) => { - for_operand(o1, &mut f, &mut self.projection_store); - for_operand(o2, &mut f, &mut self.projection_store); + for_operand(o1, &mut f); + for_operand(o2, &mut f); } Rvalue::Aggregate(_, ops) => { for op in ops.iter_mut() { - for_operand(op, &mut f, &mut self.projection_store); + for_operand(op, &mut f); } } Rvalue::ThreadLocalRef(n) @@ -1145,9 +1162,7 @@ impl MirBody { | Rvalue::NullaryOp(n) => match *n {}, } } - StatementKind::FakeRead(p) | StatementKind::Deinit(p) => { - f(p, &mut self.projection_store) - } + StatementKind::FakeRead(p) | StatementKind::Deinit(p) => f(p), StatementKind::StorageLive(_) | StatementKind::StorageDead(_) | StatementKind::Nop => (), @@ -1155,9 +1170,7 @@ impl MirBody { } match &mut block.terminator { Some(x) => match &mut x.kind { - TerminatorKind::SwitchInt { discr, .. } => { - for_operand(discr, &mut f, &mut self.projection_store) - } + TerminatorKind::SwitchInt { discr, .. } => for_operand(discr, &mut f), TerminatorKind::FalseEdge { .. } | TerminatorKind::FalseUnwind { .. } | TerminatorKind::Goto { .. } @@ -1167,24 +1180,23 @@ impl MirBody { | TerminatorKind::Return | TerminatorKind::Unreachable => (), TerminatorKind::Drop { place, .. } => { - f(place, &mut self.projection_store); + f(place); } TerminatorKind::DropAndReplace { place, value, .. } => { - f(place, &mut self.projection_store); - for_operand(value, &mut f, &mut self.projection_store); + f(place); + for_operand(value, &mut f); } TerminatorKind::Call { func, args, destination, .. } => { - for_operand(func, &mut f, &mut self.projection_store); - args.iter_mut() - .for_each(|x| for_operand(x, &mut f, &mut self.projection_store)); - f(destination, &mut self.projection_store); + for_operand(func, &mut f); + args.iter_mut().for_each(|x| for_operand(x, &mut f)); + f(destination); } TerminatorKind::Assert { cond, .. } => { - for_operand(cond, &mut f, &mut self.projection_store); + for_operand(cond, &mut f); } TerminatorKind::Yield { value, resume_arg, .. } => { - for_operand(value, &mut f, &mut self.projection_store); - f(resume_arg, &mut self.projection_store); + for_operand(value, &mut f); + f(resume_arg); } }, None => (), @@ -1202,9 +1214,7 @@ impl MirBody { upvar_locals, param_locals, closures, - projection_store, } = self; - projection_store.shrink_to_fit(); basic_blocks.shrink_to_fit(); locals.shrink_to_fit(); binding_locals.shrink_to_fit(); diff --git a/crates/hir-ty/src/mir/borrowck.rs b/crates/hir-ty/src/mir/borrowck.rs index bc158ac884..ff963fc121 100644 --- a/crates/hir-ty/src/mir/borrowck.rs +++ b/crates/hir-ty/src/mir/borrowck.rs @@ -195,11 +195,11 @@ fn moved_out_of_ref<'db>( ) -> Vec<MovedOutOfRef> { let db = infcx.interner.db; let mut result = vec![]; - let mut for_operand = |op: &Operand, span: MirSpan| match op.kind { + let mut for_operand = |op: &Operand, span: MirSpan| match &op.kind { OperandKind::Copy(p) | OperandKind::Move(p) => { let mut ty: Ty<'db> = body.locals[p.local].ty.as_ref(); let mut is_dereference_of_ref = false; - for proj in p.projection.lookup(&body.projection_store) { + for proj in p.projection.lookup() { if *proj == ProjectionElem::Deref && ty.as_reference().is_some() { is_dereference_of_ref = true; } @@ -290,10 +290,10 @@ fn partially_moved<'db>( ) -> Vec<PartiallyMoved> { let db = infcx.interner.db; let mut result = vec![]; - let mut for_operand = |op: &Operand, span: MirSpan| match op.kind { + let mut for_operand = |op: &Operand, span: MirSpan| match &op.kind { OperandKind::Copy(p) | OperandKind::Move(p) => { let mut ty: Ty<'db> = body.locals[p.local].ty.as_ref(); - for proj in p.projection.lookup(&body.projection_store) { + for proj in p.projection.lookup() { ty = proj.projected_ty(infcx, env, ty, body.owner.module(db).krate(db)); } if !infcx.type_is_copy_modulo_regions(env, ty) && !ty.references_non_lt_error() { @@ -430,7 +430,7 @@ fn place_case<'db>( let db = infcx.interner.db; let mut is_part_of = false; let mut ty = body.locals[lvalue.local].ty.as_ref(); - for proj in lvalue.projection.lookup(&body.projection_store).iter() { + for proj in lvalue.projection.lookup().iter() { match proj { 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>` @@ -470,7 +470,7 @@ fn ever_initialized_map( for statement in &block.statements { match &statement.kind { StatementKind::Assign(p, _) => { - if p.projection.lookup(&body.projection_store).is_empty() && p.local == l { + if p.projection.is_empty() && p.local == l { is_ever_initialized = true; } } @@ -508,9 +508,7 @@ fn ever_initialized_map( | TerminatorKind::Return | TerminatorKind::Unreachable => (), TerminatorKind::Call { target, cleanup, destination, .. } => { - if destination.projection.lookup(&body.projection_store).is_empty() - && destination.local == l - { + if destination.projection.is_empty() && destination.local == l { is_ever_initialized = true; } target.iter().chain(cleanup).for_each(|&it| process(it, is_ever_initialized)); @@ -566,7 +564,7 @@ fn record_usage(local: LocalId, result: &mut ArenaMap<LocalId, MutabilityReason> } fn record_usage_for_operand(arg: &Operand, result: &mut ArenaMap<LocalId, MutabilityReason>) { - if let OperandKind::Copy(p) | OperandKind::Move(p) = arg.kind { + if let OperandKind::Copy(p) | OperandKind::Move(p) = &arg.kind { record_usage(p.local, result); } } @@ -674,7 +672,7 @@ fn mutability_of_locals<'db>( for arg in args.iter() { record_usage_for_operand(arg, &mut result); } - if destination.projection.lookup(&body.projection_store).is_empty() { + if destination.projection.is_empty() { if ever_init_map.get(destination.local).copied().unwrap_or_default() { push_mut_span(destination.local, terminator.span, &mut result); } else { diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs index 1ee18e09ba..78b70edeee 100644 --- a/crates/hir-ty/src/mir/eval.rs +++ b/crates/hir-ty/src/mir/eval.rs @@ -56,7 +56,7 @@ use crate::{ use super::{ AggregateKind, BasicBlockId, BinOp, CastKind, LocalId, MirBody, MirLowerError, MirSpan, - Operand, OperandKind, Place, PlaceElem, ProjectionElem, ProjectionStore, Rvalue, StatementKind, + Operand, OperandKind, Place, PlaceElem, PlaceRef, ProjectionElem, Rvalue, StatementKind, TerminatorKind, UnOp, return_slot, }; @@ -567,26 +567,26 @@ impl std::fmt::Debug for MirEvalError { type Result<'db, T> = std::result::Result<T, MirEvalError>; #[derive(Debug, Default)] -struct DropFlags { - need_drop: FxHashSet<Place>, +struct DropFlags<'db> { + need_drop: FxHashSet<PlaceRef<'db>>, } -impl DropFlags { - fn add_place(&mut self, p: Place, store: &ProjectionStore) { - if p.iterate_over_parents(store).any(|it| self.need_drop.contains(&it)) { +impl<'db> DropFlags<'db> { + fn add_place(&mut self, p: PlaceRef<'db>) { + if p.iterate_over_parents().any(|it| self.need_drop.contains(&it)) { return; } - self.need_drop.retain(|it| !p.is_parent(it, store)); + self.need_drop.retain(|it| !p.is_parent(*it)); self.need_drop.insert(p); } - fn remove_place(&mut self, p: &Place, store: &ProjectionStore) -> bool { + fn remove_place(&mut self, p: PlaceRef<'db>) -> bool { // FIXME: replace parents with parts - if let Some(parent) = p.iterate_over_parents(store).find(|it| self.need_drop.contains(it)) { + if let Some(parent) = p.iterate_over_parents().find(|it| self.need_drop.contains(it)) { self.need_drop.remove(&parent); return true; } - self.need_drop.remove(p) + self.need_drop.remove(&p) } fn clear(&mut self) { @@ -598,7 +598,7 @@ impl DropFlags { struct Locals<'a> { ptr: ArenaMap<LocalId, Interval>, body: &'a MirBody, - drop_flags: DropFlags, + drop_flags: DropFlags<'a>, } pub struct MirOutput { @@ -757,9 +757,9 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { let mut addr = locals.ptr[p.local].addr; let mut ty: Ty<'db> = locals.body.locals[p.local].ty.as_ref(); let mut metadata: Option<IntervalOrOwned> = None; // locals are always sized - for proj in p.projection.lookup(&locals.body.projection_store) { + for proj in p.projection.lookup() { let prev_ty = ty; - ty = self.projected_ty(ty, proj.clone()); + ty = self.projected_ty(ty, *proj); match proj { ProjectionElem::Deref => { metadata = if self.size_align_of(ty, locals)?.is_none() { @@ -955,7 +955,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { let addr = self.place_addr(l, locals)?; let result = self.eval_rvalue(r, locals)?; self.copy_from_interval_or_owned(addr, result)?; - locals.drop_flags.add_place(*l, &locals.body.projection_store); + locals.drop_flags.add_place(l.as_ref()); } StatementKind::Deinit(_) => not_supported!("de-init statement"), StatementKind::StorageLive(_) @@ -1008,9 +1008,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { )?, it => not_supported!("unknown function type {it:?}"), }; - locals - .drop_flags - .add_place(*destination, &locals.body.projection_store); + locals.drop_flags.add_place(destination.as_ref()); if let Some(stack_frame) = stack_frame { self.code_stack.push(my_stack_frame); current_block_idx = stack_frame.locals.body.start_block; @@ -1091,7 +1089,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { ) -> Result<'db, ()> { 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(), &locals.body.projection_store); + 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)?, @@ -1915,7 +1913,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { 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); + locals.drop_flags.remove_place(p.as_ref()); self.eval_place(p, locals)? } OperandKind::Static(st) => { @@ -3036,7 +3034,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { 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) { + if !locals.drop_flags.remove_place(place.as_ref()) { return Ok(()); } let metadata = match metadata { diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs index 394cac8065..4e52c1f7c3 100644 --- a/crates/hir-ty/src/mir/lower.rs +++ b/crates/hir-ty/src/mir/lower.rs @@ -45,9 +45,9 @@ use crate::{ mir::{ AggregateKind, Arena, BasicBlock, BasicBlockId, BinOp, BorrowKind, CastKind, Either, Expr, FieldId, GenericArgs, Idx, InferenceResult, Local, LocalId, MemoryMap, MirBody, MirSpan, - Mutability, Operand, Place, PlaceElem, PointerCast, ProjectionElem, ProjectionStore, - RawIdx, Rvalue, Statement, StatementKind, SwitchTargets, Terminator, TerminatorKind, - TupleFieldId, Ty, UnOp, VariantId, return_slot, + Mutability, Operand, Place, PlaceElem, PointerCast, Projection, ProjectionElem, RawIdx, + Rvalue, Statement, StatementKind, SwitchTargets, Terminator, TerminatorKind, TupleFieldId, + Ty, UnOp, VariantId, return_slot, }, next_solver::{ Const, DbInterner, ParamConst, ParamEnv, Region, StoredGenericArgs, StoredTy, TyKind, @@ -57,7 +57,7 @@ use crate::{ }, }; -use super::OperandKind; +use super::{OperandKind, PlaceRef}; mod as_place; mod pattern_matching; @@ -303,7 +303,6 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { let locals = Arena::new(); let binding_locals: ArenaMap<BindingId, LocalId> = ArenaMap::new(); let mir = MirBody { - projection_store: ProjectionStore::default(), basic_blocks, locals, start_block, @@ -371,13 +370,16 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { let Some((p, current)) = self.lower_expr_as_place(current, expr_id, true)? else { return Ok(None); }; - Ok(Some((Operand { kind: OperandKind::Copy(p), span: Some(expr_id.into()) }, current))) + Ok(Some(( + Operand { kind: OperandKind::Copy(p.store()), span: Some(expr_id.into()) }, + current, + ))) } fn lower_expr_to_place_with_adjust( &mut self, expr_id: ExprId, - place: Place, + place: PlaceRef<'db>, current: BasicBlockId, adjustments: &[Adjustment], ) -> Result<'db, Option<BasicBlockId>> { @@ -396,7 +398,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { self.push_assignment( current, place, - Operand { kind: OperandKind::Copy(p), span: None }.into(), + Operand { kind: OperandKind::Copy(p.store()), span: None }.into(), expr_id.into(), ); Ok(Some(current)) @@ -422,7 +424,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { place, Rvalue::Cast( CastKind::PointerCoercion(*cast), - Operand { kind: OperandKind::Copy(p), span: None }, + Operand { kind: OperandKind::Copy(p.store()), span: None }, last.target.clone(), ), expr_id.into(), @@ -437,7 +439,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { fn lower_expr_to_place_with_borrow_adjust( &mut self, expr_id: ExprId, - place: Place, + place: PlaceRef<'db>, current: BasicBlockId, rest: &[Adjustment], m: Mutability, @@ -448,14 +450,14 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { return Ok(None); }; let bk = BorrowKind::from_rustc_mutability(m); - self.push_assignment(current, place, Rvalue::Ref(bk, p), expr_id.into()); + self.push_assignment(current, place, Rvalue::Ref(bk, p.store()), expr_id.into()); Ok(Some(current)) } fn lower_expr_to_place( &mut self, expr_id: ExprId, - place: Place, + place: PlaceRef<'db>, prev_block: BasicBlockId, ) -> Result<'db, Option<BasicBlockId>> { if let Some(adjustments) = self.infer.expr_adjustments.get(&expr_id) { @@ -467,7 +469,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { fn lower_expr_to_place_without_adjust( &mut self, expr_id: ExprId, - place: Place, + place: PlaceRef<'db>, mut current: BasicBlockId, ) -> Result<'db, Option<BasicBlockId>> { match &self.store[expr_id] { @@ -535,7 +537,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { self.push_assignment( current, place, - Operand { kind: OperandKind::Copy(temp), span: None }.into(), + Operand { kind: OperandKind::Copy(temp.store()), span: None }.into(), expr_id.into(), ); Ok(Some(current)) @@ -831,7 +833,9 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { .as_ref() .ok_or(MirLowerError::BreakWithoutLoop)?, }; - let Some(c) = self.lower_expr_to_place(expr, loop_data.place, current)? else { + let Some(c) = + self.lower_expr_to_place(expr, loop_data.place.as_ref(), current)? + else { return Ok(None); }; current = c; @@ -921,16 +925,18 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { .map(|(i, it)| match it { Some(it) => it, None => { - let p = sp.project( - ProjectionElem::Field(Either::Left(FieldId { + let p = sp.project(ProjectionElem::Field( + Either::Left(FieldId { parent: variant_id, local_id: LocalFieldId::from_raw(RawIdx::from( i as u32, )), - })), - &mut self.result.projection_store, - ); - Operand { kind: OperandKind::Copy(p), span: None } + }), + )); + Operand { + kind: OperandKind::Copy(p.store()), + span: None, + } } }) .collect(), @@ -948,13 +954,10 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { }; let local_id = variant_fields.field(name).ok_or(MirLowerError::UnresolvedField)?; - let place = place.project( - PlaceElem::Field(Either::Left(FieldId { - parent: union_id.into(), - local_id, - })), - &mut self.result.projection_store, - ); + let place = place.project(PlaceElem::Field(Either::Left(FieldId { + parent: union_id.into(), + local_id, + }))); self.lower_expr_to_place(*expr, place, current) } } @@ -1001,7 +1004,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { return Ok(None); }; let bk = BorrowKind::from_hir_mutability(*mutability); - self.push_assignment(current, place, Rvalue::Ref(bk, p), expr_id.into()); + self.push_assignment(current, place, Rvalue::Ref(bk, p.store()), expr_id.into()); Ok(Some(current)) } Expr::Box { expr } => { @@ -1016,7 +1019,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { else { return Ok(None); }; - let p = place.project(ProjectionElem::Deref, &mut self.result.projection_store); + let p = place.project(ProjectionElem::Deref); self.push_assignment(current, p, operand.into(), expr_id.into()); Ok(Some(current)) } @@ -1031,7 +1034,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { self.push_assignment( current, place, - Operand { kind: OperandKind::Copy(p), span: None }.into(), + Operand { kind: OperandKind::Copy(p.store()), span: None }.into(), expr_id.into(), ); Ok(Some(current)) @@ -1124,7 +1127,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { }; let r_value = Rvalue::CheckedBinaryOp( op.into(), - Operand { kind: OperandKind::Copy(lhs_place), span: None }, + Operand { kind: OperandKind::Copy(lhs_place.store()), span: None }, rhs_op, ); self.push_assignment(current, lhs_place, r_value, expr_id.into()); @@ -1273,16 +1276,16 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { }; Ok(Place { local: this.binding_local(local)?, - projection: this - .result - .projection_store - .intern(convert_closure_capture_projections(self.db, place).collect()), + projection: Projection::new_from_iter(convert_closure_capture_projections( + self.db, place, + )) + .store(), }) }; for (place, _, sources) in &closure_data.fake_reads { let p = convert_place(self, place)?; - self.push_fake_read(current, p, span(sources)); + self.push_fake_read(current, p.as_ref(), span(sources)); } let captures = closure_data.min_captures.values().flatten(); @@ -1294,14 +1297,15 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { let tmp_ty = capture.captured_ty(self.db); // FIXME: Handle more than one span. let capture_span = span(&capture.info.sources); - let tmp: Place = self.temp(tmp_ty, current, capture_span)?.into(); + let tmp = self.temp(tmp_ty, current, capture_span)?.into(); self.push_assignment( current, tmp, Rvalue::Ref(BorrowKind::from_hir(bk), p), capture_span, ); - operands.push(Operand { kind: OperandKind::Move(tmp), span: None }); + operands + .push(Operand { kind: OperandKind::Move(tmp.store()), span: None }); } UpvarCapture::ByValue => { operands.push(Operand { kind: OperandKind::Move(p), span: None }) @@ -1396,24 +1400,24 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { } } - fn push_field_projection(&mut self, place: &mut Place, expr_id: ExprId) -> Result<'db, ()> { + fn push_field_projection( + &mut self, + place: &mut PlaceRef<'db>, + expr_id: ExprId, + ) -> Result<'db, ()> { if let Expr::Field { expr, name } = &self.store[expr_id] { if let TyKind::Tuple(..) = self.expr_ty_after_adjustments(*expr).kind() { let index = name.as_tuple_index().ok_or(MirLowerError::TypeError("named field on tuple"))? as u32; - *place = place.project( - ProjectionElem::Field(Either::Right(TupleFieldId { - tuple: TupleId(!0), // dummy as its unused - index, - })), - &mut self.result.projection_store, - ) + *place = place.project(ProjectionElem::Field(Either::Right(TupleFieldId { + tuple: TupleId(!0), // dummy as its unused + index, + }))) } else { let field = self.infer.field_resolution(expr_id).ok_or(MirLowerError::UnresolvedField)?; - *place = - place.project(ProjectionElem::Field(field), &mut self.result.projection_store); + *place = place.project(ProjectionElem::Field(field)); } } else { not_supported!("") @@ -1528,7 +1532,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { &mut self, const_id: GeneralConstId, prev_block: BasicBlockId, - place: Place, + place: PlaceRef<'db>, subst: GenericArgs<'db>, span: MirSpan, ) -> Result<'db, ()> { @@ -1561,7 +1565,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { fn write_bytes_to_place( &mut self, prev_block: BasicBlockId, - place: Place, + place: PlaceRef<'db>, cv: Box<[u8]>, ty: Ty<'db>, span: MirSpan, @@ -1574,7 +1578,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { &mut self, variant_id: EnumVariantId, prev_block: BasicBlockId, - place: Place, + place: PlaceRef<'db>, ty: Ty<'db>, fields: Box<[Operand]>, span: MirSpan, @@ -1596,7 +1600,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { &mut self, func: Operand, args: impl Iterator<Item = ExprId>, - place: Place, + place: PlaceRef<'db>, mut current: BasicBlockId, is_uninhabited: bool, span: MirSpan, @@ -1621,7 +1625,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { &mut self, func: Operand, args: Box<[Operand]>, - place: Place, + place: PlaceRef<'db>, current: BasicBlockId, is_uninhabited: bool, span: MirSpan, @@ -1632,7 +1636,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { TerminatorKind::Call { func, args, - destination: place, + destination: place.store(), target: b, cleanup: None, from_hir_call: true, @@ -1672,31 +1676,31 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { self.result.basic_blocks[block].statements.push(statement); } - fn push_fake_read(&mut self, block: BasicBlockId, p: Place, span: MirSpan) { - self.push_statement(block, StatementKind::FakeRead(p).with_span(span)); + fn push_fake_read(&mut self, block: BasicBlockId, p: PlaceRef<'db>, span: MirSpan) { + self.push_statement(block, StatementKind::FakeRead(p.store()).with_span(span)); } fn push_assignment( &mut self, block: BasicBlockId, - place: Place, + place: PlaceRef<'db>, rvalue: Rvalue, span: MirSpan, ) { - self.push_statement(block, StatementKind::Assign(place, rvalue).with_span(span)); + self.push_statement(block, StatementKind::Assign(place.store(), rvalue).with_span(span)); } - fn discr_temp_place(&mut self, current: BasicBlockId) -> Place { + fn discr_temp_place(&mut self, current: BasicBlockId) -> PlaceRef<'db> { match &self.discr_temp { - Some(it) => *it, + Some(it) => it.as_ref(), None => { // FIXME: rustc's ty is dependent on the adt type, maybe we need to do that as well let discr_ty = Ty::new_int(self.interner(), rustc_type_ir::IntTy::I128); - let tmp: Place = self + let tmp: PlaceRef<'_> = self .temp(discr_ty, current, MirSpan::Unknown) .expect("discr_ty is never unsized") .into(); - self.discr_temp = Some(tmp); + self.discr_temp = Some(tmp.store()); tmp } } @@ -1705,7 +1709,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { fn lower_loop( &mut self, prev_block: BasicBlockId, - place: Place, + place: PlaceRef<'db>, label: Option<LabelId>, span: MirSpan, f: impl FnOnce(&mut MirLowerCtx<'_, 'db>, BasicBlockId) -> Result<'db, ()>, @@ -1714,7 +1718,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { let prev = self.current_loop_blocks.replace(LoopBlocks { begin, end: None, - place, + place: place.store(), drop_scope_index: self.drop_scopes.len(), }); let prev_label = if let Some(label) = label { @@ -1816,7 +1820,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { statements: &[hir_def::hir::Statement], mut current: BasicBlockId, tail: Option<ExprId>, - place: Place, + place: PlaceRef<'db>, span: MirSpan, ) -> Result<'db, Option<Idx<BasicBlock>>> { let scope = self.push_drop_scope(); @@ -2068,7 +2072,11 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { let prev = std::mem::replace(current, self.new_basic_block()); self.set_terminator( prev, - TerminatorKind::Drop { place: l.into(), target: *current, unwind: None }, + TerminatorKind::Drop { + place: PlaceRef::from(l).store(), + target: *current, + unwind: None, + }, span, ); } @@ -2202,15 +2210,18 @@ pub fn mir_body_for_closure_query<'db>( projections.push(ProjectionElem::ClosureField(capture_idx)); let capture_param_place = Place { local: closure_local, - projection: ctx.result.projection_store.intern(projections.into_boxed_slice()), - }; - let capture_local_place = Place { - local: capture_local, - projection: ctx.result.projection_store.intern(Box::new([])), + projection: Projection::new_from_slice(&projections).store(), }; + let capture_local_place = + Place { local: capture_local, projection: Projection::new_from_slice(&[]).store() }; let capture_local_rvalue = Rvalue::Use(Operand { kind: OperandKind::Move(capture_param_place), span: None }); - ctx.push_assignment(current, capture_local_place, capture_local_rvalue, MirSpan::Unknown); + ctx.push_assignment( + current, + capture_local_place.as_ref(), + capture_local_rvalue, + MirSpan::Unknown, + ); let local = capture.captured_local(); let local = ctx.binding_local(local)?; @@ -2230,8 +2241,8 @@ pub fn mir_body_for_closure_query<'db>( } let mut err = None; - ctx.result.walk_places(|mir_place, store| { - let mir_projections = mir_place.projection.lookup(store); + ctx.result.walk_places(|mir_place| { + let mir_projections = mir_place.projection.lookup(); if let Some(hir_places) = upvar_map.get(&mir_place.local) { let projections = hir_places.iter().find_map(|hir_place| { let iter = mir_projections @@ -2267,18 +2278,17 @@ pub fn mir_body_for_closure_query<'db>( match projections { Some((skip_projections_up_to, (hir_place, upvar_local))) => { mir_place.local = *upvar_local; - let mut result_projections = Vec::with_capacity( - usize::from(hir_place.is_by_ref()) - + (mir_projections.len() - skip_projections_up_to), - ); - if hir_place.is_by_ref() { - result_projections.push(ProjectionElem::Deref); - } - result_projections - .extend(mir_projections[skip_projections_up_to..].iter().cloned()); - mir_place.projection = store.intern(result_projections.into()); + let maybe_deref: &[PlaceElem] = + if hir_place.is_by_ref() { &[ProjectionElem::Deref] } else { &[] }; + mir_place.projection = Projection::new_from_iter( + maybe_deref + .iter() + .copied() + .chain(mir_projections[skip_projections_up_to..].iter().copied()), + ) + .store(); } - None => err = Some(*mir_place), + None => err = Some(mir_place.clone()), } } }); diff --git a/crates/hir-ty/src/mir/lower/as_place.rs b/crates/hir-ty/src/mir/lower/as_place.rs index 2ed7aedecf..bb00a79480 100644 --- a/crates/hir-ty/src/mir/lower/as_place.rs +++ b/crates/hir-ty/src/mir/lower/as_place.rs @@ -14,15 +14,14 @@ impl<'db> MirLowerCtx<'_, 'db> { &mut self, expr_id: ExprId, prev_block: BasicBlockId, - ) -> Result<'db, Option<(Place, BasicBlockId)>> { + ) -> Result<'db, Option<(PlaceRef<'db>, BasicBlockId)>> { let ty = self.expr_ty_without_adjust(expr_id); - let place = self.temp(ty, prev_block, expr_id.into())?; - let Some(current) = - self.lower_expr_to_place_without_adjust(expr_id, place.into(), prev_block)? + let place = self.temp(ty, prev_block, expr_id.into())?.into(); + let Some(current) = self.lower_expr_to_place_without_adjust(expr_id, place, prev_block)? else { return Ok(None); }; - Ok(Some((place.into(), current))) + Ok(Some((place, current))) } fn lower_expr_to_some_place_with_adjust( @@ -30,18 +29,18 @@ impl<'db> MirLowerCtx<'_, 'db> { expr_id: ExprId, prev_block: BasicBlockId, adjustments: &[Adjustment], - ) -> Result<'db, Option<(Place, BasicBlockId)>> { + ) -> Result<'db, Option<(PlaceRef<'db>, BasicBlockId)>> { let ty = adjustments .last() .map(|it| it.target.as_ref()) .unwrap_or_else(|| self.expr_ty_without_adjust(expr_id)); - let place = self.temp(ty, prev_block, expr_id.into())?; + let place = self.temp(ty, prev_block, expr_id.into())?.into(); let Some(current) = - self.lower_expr_to_place_with_adjust(expr_id, place.into(), prev_block, adjustments)? + self.lower_expr_to_place_with_adjust(expr_id, place, prev_block, adjustments)? else { return Ok(None); }; - Ok(Some((place.into(), current))) + Ok(Some((place, current))) } pub(super) fn lower_expr_as_place_with_adjust( @@ -50,7 +49,7 @@ impl<'db> MirLowerCtx<'_, 'db> { expr_id: ExprId, upgrade_rvalue: bool, adjustments: &[Adjustment], - ) -> Result<'db, Option<(Place, BasicBlockId)>> { + ) -> Result<'db, Option<(PlaceRef<'db>, BasicBlockId)>> { let try_rvalue = |this: &mut MirLowerCtx<'_, 'db>| { if !upgrade_rvalue { return Err(MirLowerError::MutatingRvalue); @@ -69,7 +68,7 @@ impl<'db> MirLowerCtx<'_, 'db> { else { return Ok(None); }; - it.0 = it.0.project(ProjectionElem::Deref, &mut self.result.projection_store); + it.0 = it.0.project(ProjectionElem::Deref); Ok(Some(it)) } Adjust::Deref(Some(od)) => { @@ -108,7 +107,7 @@ impl<'db> MirLowerCtx<'_, 'db> { current: BasicBlockId, expr_id: ExprId, upgrade_rvalue: bool, - ) -> Result<'db, Option<(Place, BasicBlockId)>> { + ) -> Result<'db, Option<(PlaceRef<'db>, BasicBlockId)>> { match self.infer.expr_adjustments.get(&expr_id) { Some(a) => self.lower_expr_as_place_with_adjust(current, expr_id, upgrade_rvalue, a), None => self.lower_expr_as_place_without_adjust(current, expr_id, upgrade_rvalue), @@ -120,7 +119,7 @@ impl<'db> MirLowerCtx<'_, 'db> { current: BasicBlockId, expr_id: ExprId, upgrade_rvalue: bool, - ) -> Result<'db, Option<(Place, BasicBlockId)>> { + ) -> Result<'db, Option<(PlaceRef<'db>, BasicBlockId)>> { let try_rvalue = |this: &mut MirLowerCtx<'_, 'db>| { if !upgrade_rvalue { return Err(MirLowerError::MutatingRvalue); @@ -149,17 +148,14 @@ impl<'db> MirLowerCtx<'_, 'db> { ty, Mutability::Not, ); - let temp: Place = self.temp(ref_ty, current, expr_id.into())?.into(); + let temp = self.temp(ref_ty, current, expr_id.into())?.into(); self.push_assignment( current, temp, Operand { kind: OperandKind::Static(s), span: None }.into(), expr_id.into(), ); - Ok(Some(( - temp.project(ProjectionElem::Deref, &mut self.result.projection_store), - current, - ))) + Ok(Some((temp.project(ProjectionElem::Deref), current))) } _ => try_rvalue(self), } @@ -193,7 +189,7 @@ impl<'db> MirLowerCtx<'_, 'db> { let Some((mut r, current)) = self.lower_expr_as_place(current, *expr, true)? else { return Ok(None); }; - r = r.project(ProjectionElem::Deref, &mut self.result.projection_store); + r = r.project(ProjectionElem::Deref); Ok(Some((r, current))) } Expr::UnaryOp { .. } => try_rvalue(self), @@ -256,8 +252,7 @@ impl<'db> MirLowerCtx<'_, 'db> { else { return Ok(None); }; - p_base = p_base - .project(ProjectionElem::Index(l_index), &mut self.result.projection_store); + p_base = p_base.project(ProjectionElem::Index(l_index)); Ok(Some((p_base, current))) } _ => try_rvalue(self), @@ -267,20 +262,20 @@ impl<'db> MirLowerCtx<'_, 'db> { fn lower_overloaded_index( &mut self, current: BasicBlockId, - place: Place, + place: PlaceRef<'db>, base_ty: Ty<'db>, result_ty: Ty<'db>, index_operand: Operand, span: MirSpan, index_fn: (FunctionId, GenericArgs<'db>), - ) -> Result<'db, Option<(Place, BasicBlockId)>> { + ) -> Result<'db, Option<(PlaceRef<'db>, BasicBlockId)>> { let mutability = match base_ty.as_reference() { Some((_, _, mutability)) => mutability, None => Mutability::Not, }; let result_ref = Ty::new_ref(self.interner(), Region::error(self.interner()), result_ty, mutability); - let mut result: Place = self.temp(result_ref, current, span)?.into(); + let mut result = self.temp(result_ref, current, span)?.into(); let index_fn_op = Operand::const_zst(Ty::new_fn_def( self.interner(), CallableDefId::FunctionId(index_fn.0).into(), @@ -288,7 +283,10 @@ impl<'db> MirLowerCtx<'_, 'db> { )); let Some(current) = self.lower_call( index_fn_op, - Box::new([Operand { kind: OperandKind::Copy(place), span: None }, index_operand]), + Box::new([ + Operand { kind: OperandKind::Copy(place.store()), span: None }, + index_operand, + ]), result, current, false, @@ -297,19 +295,19 @@ impl<'db> MirLowerCtx<'_, 'db> { else { return Ok(None); }; - result = result.project(ProjectionElem::Deref, &mut self.result.projection_store); + result = result.project(ProjectionElem::Deref); Ok(Some((result, current))) } fn lower_overloaded_deref( &mut self, current: BasicBlockId, - place: Place, + place: PlaceRef<'db>, source_ty: Ty<'db>, target_ty: Ty<'db>, span: MirSpan, mutability: bool, - ) -> Result<'db, Option<(Place, BasicBlockId)>> { + ) -> Result<'db, Option<(PlaceRef<'db>, BasicBlockId)>> { let lang_items = self.lang_items(); let (mutability, deref_fn, borrow_kind) = if !mutability { (Mutability::Not, lang_items.Deref_deref, BorrowKind::Shared) @@ -323,18 +321,18 @@ impl<'db> MirLowerCtx<'_, 'db> { let error_region = Region::error(self.interner()); let ty_ref = Ty::new_ref(self.interner(), error_region, source_ty, mutability); let target_ty_ref = Ty::new_ref(self.interner(), error_region, target_ty, mutability); - let ref_place: Place = self.temp(ty_ref, current, span)?.into(); - self.push_assignment(current, ref_place, Rvalue::Ref(borrow_kind, place), span); + let ref_place = self.temp(ty_ref, current, span)?.into(); + self.push_assignment(current, ref_place, Rvalue::Ref(borrow_kind, place.store()), span); let deref_fn = deref_fn.ok_or(MirLowerError::LangItemNotFound)?; let deref_fn_op = Operand::const_zst(Ty::new_fn_def( self.interner(), CallableDefId::FunctionId(deref_fn).into(), GenericArgs::new_from_slice(&[source_ty.into()]), )); - let mut result: Place = self.temp(target_ty_ref, current, span)?.into(); + let mut result = self.temp(target_ty_ref, current, span)?.into(); let Some(current) = self.lower_call( deref_fn_op, - Box::new([Operand { kind: OperandKind::Copy(ref_place), span: None }]), + Box::new([Operand { kind: OperandKind::Copy(ref_place.store()), span: None }]), result, current, false, @@ -343,7 +341,7 @@ impl<'db> MirLowerCtx<'_, 'db> { else { return Ok(None); }; - result = result.project(ProjectionElem::Deref, &mut self.result.projection_store); + result = result.project(ProjectionElem::Deref); Ok(Some((result, current))) } } diff --git a/crates/hir-ty/src/mir/lower/pattern_matching.rs b/crates/hir-ty/src/mir/lower/pattern_matching.rs index 2cb2143229..c306b6ca15 100644 --- a/crates/hir-ty/src/mir/lower/pattern_matching.rs +++ b/crates/hir-ty/src/mir/lower/pattern_matching.rs @@ -6,10 +6,10 @@ use rustc_type_ir::inherent::{IntoKind, Ty as _}; use crate::{ BindingMode, ByRef, mir::{ - LocalId, MutBorrowKind, Operand, OperandKind, + LocalId, MutBorrowKind, Operand, OperandKind, PlaceRef, Projection, lower::{ BasicBlockId, BinOp, BindingId, BorrowKind, Either, Expr, FieldId, Idx, MemoryMap, - MirLowerCtx, MirLowerError, MirSpan, Pat, PatId, Place, PlaceElem, ProjectionElem, + MirLowerCtx, MirLowerError, MirSpan, Pat, PatId, PlaceElem, ProjectionElem, RecordFieldPat, ResolveValueResult, Result, Rvalue, SwitchTargets, TerminatorKind, TupleFieldId, TupleId, Ty, TyKind, ValueNs, VariantId, }, @@ -65,7 +65,7 @@ impl<'db> MirLowerCtx<'_, 'db> { &mut self, current: BasicBlockId, current_else: Option<BasicBlockId>, - cond_place: Place, + cond_place: PlaceRef<'db>, pattern: PatId, ) -> Result<'db, (BasicBlockId, Option<BasicBlockId>)> { let (current, current_else) = self.pattern_match_inner( @@ -88,7 +88,7 @@ impl<'db> MirLowerCtx<'_, 'db> { pub(super) fn pattern_match_assignment( &mut self, current: BasicBlockId, - value: Place, + value: PlaceRef<'db>, pattern: PatId, ) -> Result<'db, BasicBlockId> { let (current, _) = @@ -116,20 +116,18 @@ impl<'db> MirLowerCtx<'_, 'db> { &mut self, mut current: BasicBlockId, mut current_else: Option<BasicBlockId>, - mut cond_place: Place, + mut cond_place: PlaceRef<'db>, pattern: PatId, mode: MatchingMode, ) -> Result<'db, (BasicBlockId, Option<BasicBlockId>)> { let cnt = self.infer.pat_adjustments.get(&pattern).map(|x| x.len()).unwrap_or_default(); - cond_place.projection = self.result.projection_store.intern( + cond_place.projection = Projection::new_from_iter( cond_place .projection - .lookup(&self.result.projection_store) + .as_slice() .iter() .cloned() - .chain((0..cnt).map(|_| ProjectionElem::Deref)) - .collect::<Vec<_>>() - .into(), + .chain((0..cnt).map(|_| ProjectionElem::Deref)), ); Ok(match &self.store[pattern] { Pat::Missing | Pat::Rest | Pat::NotNull => { @@ -215,7 +213,7 @@ impl<'db> MirLowerCtx<'_, 'db> { self.lower_literal_or_const_to_operand(self.infer.pat_ty(pattern), l)?; let else_target = *current_else.get_or_insert_with(|| self.new_basic_block()); let next = self.new_basic_block(); - let discr: Place = + let discr = self.temp(Ty::new_bool(self.interner()), current, pattern.into())?.into(); self.push_assignment( current, @@ -223,11 +221,11 @@ impl<'db> MirLowerCtx<'_, 'db> { Rvalue::CheckedBinaryOp( binop, lv, - Operand { kind: OperandKind::Copy(cond_place), span: None }, + Operand { kind: OperandKind::Copy(cond_place.store()), span: None }, ), pattern.into(), ); - let discr = Operand { kind: OperandKind::Copy(discr), span: None }; + let discr = Operand { kind: OperandKind::Copy(discr.store()), span: None }; self.set_terminator( current, TerminatorKind::SwitchInt { @@ -263,13 +261,13 @@ impl<'db> MirLowerCtx<'_, 'db> { // emit runtime length check for slice if let TyKind::Slice(_) = pat_ty.kind() { let pattern_len = prefix.len() + suffix.len(); - let place_len: Place = self + let place_len = self .temp(Ty::new_usize(self.interner()), current, pattern.into())? .into(); self.push_assignment( current, place_len, - Rvalue::Len(cond_place), + Rvalue::Len(cond_place.store()), pattern.into(), ); let else_target = @@ -280,7 +278,7 @@ impl<'db> MirLowerCtx<'_, 'db> { current, TerminatorKind::SwitchInt { discr: Operand { - kind: OperandKind::Copy(place_len), + kind: OperandKind::Copy(place_len.store()), span: None, }, targets: SwitchTargets::static_if( @@ -297,7 +295,7 @@ impl<'db> MirLowerCtx<'_, 'db> { MemoryMap::default(), Ty::new_usize(self.interner()), ); - let discr: Place = self + let discr = self .temp(Ty::new_bool(self.interner()), current, pattern.into())? .into(); self.push_assignment( @@ -306,11 +304,15 @@ impl<'db> MirLowerCtx<'_, 'db> { Rvalue::CheckedBinaryOp( BinOp::Le, c, - Operand { kind: OperandKind::Copy(place_len), span: None }, + Operand { + kind: OperandKind::Copy(place_len.store()), + span: None, + }, ), pattern.into(), ); - let discr = Operand { kind: OperandKind::Copy(discr), span: None }; + let discr = + Operand { kind: OperandKind::Copy(discr.store()), span: None }; self.set_terminator( current, TerminatorKind::SwitchInt { @@ -324,10 +326,10 @@ impl<'db> MirLowerCtx<'_, 'db> { } } for (i, &pat) in prefix.iter().enumerate() { - let next_place = cond_place.project( - ProjectionElem::ConstantIndex { offset: i as u64, from_end: false }, - &mut self.result.projection_store, - ); + let next_place = cond_place.project(ProjectionElem::ConstantIndex { + offset: i as u64, + from_end: false, + }); (current, current_else) = self.pattern_match_inner(current, current_else, next_place, pat, mode)?; } @@ -335,13 +337,10 @@ impl<'db> MirLowerCtx<'_, 'db> { && mode != MatchingMode::Check && let Pat::Bind { id, subpat: _ } = self.store[slice] { - let next_place = cond_place.project( - ProjectionElem::Subslice { - from: prefix.len() as u64, - to: suffix.len() as u64, - }, - &mut self.result.projection_store, - ); + let next_place = cond_place.project(ProjectionElem::Subslice { + from: prefix.len() as u64, + to: suffix.len() as u64, + }); let mode = self.infer.binding_modes[slice]; (current, current_else) = self.pattern_match_binding( id, @@ -353,10 +352,10 @@ impl<'db> MirLowerCtx<'_, 'db> { )?; } for (i, &pat) in suffix.iter().enumerate() { - let next_place = cond_place.project( - ProjectionElem::ConstantIndex { offset: i as u64, from_end: true }, - &mut self.result.projection_store, - ); + let next_place = cond_place.project(ProjectionElem::ConstantIndex { + offset: i as u64, + from_end: true, + }); (current, current_else) = self.pattern_match_inner(current, current_else, next_place, pat, mode)?; } @@ -420,19 +419,19 @@ impl<'db> MirLowerCtx<'_, 'db> { } not_supported!("path in pattern position that is not const or variant") }; - let tmp: Place = + let tmp = self.temp(self.infer.pat_ty(pattern), current, pattern.into())?.into(); let span = pattern.into(); self.lower_const(c.into(), current, tmp, subst, span)?; - let tmp2: Place = + let tmp2 = self.temp(Ty::new_bool(self.interner()), current, pattern.into())?.into(); self.push_assignment( current, tmp2, Rvalue::CheckedBinaryOp( BinOp::Eq, - Operand { kind: OperandKind::Copy(tmp), span: None }, - Operand { kind: OperandKind::Copy(cond_place), span: None }, + Operand { kind: OperandKind::Copy(tmp.store()), span: None }, + Operand { kind: OperandKind::Copy(cond_place.store()), span: None }, ), span, ); @@ -441,7 +440,7 @@ impl<'db> MirLowerCtx<'_, 'db> { self.set_terminator( current, TerminatorKind::SwitchInt { - discr: Operand { kind: OperandKind::Copy(tmp2), span: None }, + discr: Operand { kind: OperandKind::Copy(tmp2.store()), span: None }, targets: SwitchTargets::static_if(1, next, else_target), }, span, @@ -494,8 +493,7 @@ impl<'db> MirLowerCtx<'_, 'db> { )? } Pat::Ref { pat, mutability: _ } => { - let cond_place = - cond_place.project(ProjectionElem::Deref, &mut self.result.projection_store); + let cond_place = cond_place.project(ProjectionElem::Deref); self.pattern_match_inner(current, current_else, cond_place, *pat, mode)? } &Pat::Expr(expr) => { @@ -510,7 +508,7 @@ impl<'db> MirLowerCtx<'_, 'db> { self.push_assignment( current, lhs_place, - Operand { kind: OperandKind::Copy(cond_place), span: None }.into(), + Operand { kind: OperandKind::Copy(cond_place.store()), span: None }.into(), expr.into(), ); (current, current_else) @@ -525,7 +523,7 @@ impl<'db> MirLowerCtx<'_, 'db> { &mut self, id: BindingId, mode: BindingMode, - cond_place: Place, + cond_place: PlaceRef<'db>, span: MirSpan, current: BasicBlockId, current_else: Option<BasicBlockId>, @@ -541,7 +539,7 @@ impl<'db> MirLowerCtx<'_, 'db> { current: BasicBlockId, target_place: LocalId, mode: BindingMode, - cond_place: Place, + cond_place: PlaceRef<'db>, span: MirSpan, ) { self.push_assignment( @@ -549,14 +547,15 @@ impl<'db> MirLowerCtx<'_, 'db> { target_place.into(), match mode { BindingMode(ByRef::No, _) => { - Operand { kind: OperandKind::Copy(cond_place), span: None }.into() + Operand { kind: OperandKind::Copy(cond_place.store()), span: None }.into() } BindingMode(ByRef::Yes(rustc_ast_ir::Mutability::Not), _) => { - Rvalue::Ref(BorrowKind::Shared, cond_place) - } - BindingMode(ByRef::Yes(rustc_ast_ir::Mutability::Mut), _) => { - Rvalue::Ref(BorrowKind::Mut { kind: MutBorrowKind::Default }, cond_place) + Rvalue::Ref(BorrowKind::Shared, cond_place.store()) } + BindingMode(ByRef::Yes(rustc_ast_ir::Mutability::Mut), _) => Rvalue::Ref( + BorrowKind::Mut { kind: MutBorrowKind::Default }, + cond_place.store(), + ), }, span, ); @@ -567,24 +566,23 @@ impl<'db> MirLowerCtx<'_, 'db> { current_else: Option<BasicBlockId>, current: BasicBlockId, c: Operand, - cond_place: Place, + cond_place: PlaceRef<'db>, pattern: Idx<Pat>, ) -> Result<'db, (BasicBlockId, Option<BasicBlockId>)> { let then_target = self.new_basic_block(); let else_target = current_else.unwrap_or_else(|| self.new_basic_block()); - let discr: Place = - self.temp(Ty::new_bool(self.interner()), current, pattern.into())?.into(); + let discr = self.temp(Ty::new_bool(self.interner()), current, pattern.into())?.into(); self.push_assignment( current, discr, Rvalue::CheckedBinaryOp( BinOp::Eq, c, - Operand { kind: OperandKind::Copy(cond_place), span: None }, + Operand { kind: OperandKind::Copy(cond_place.store()), span: None }, ), pattern.into(), ); - let discr = Operand { kind: OperandKind::Copy(discr), span: None }; + let discr = Operand { kind: OperandKind::Copy(discr.store()), span: None }; self.set_terminator( current, TerminatorKind::SwitchInt { @@ -598,7 +596,7 @@ impl<'db> MirLowerCtx<'_, 'db> { fn pattern_matching_variant( &mut self, - cond_place: Place, + cond_place: PlaceRef<'db>, variant: VariantId, mut current: BasicBlockId, span: MirSpan, @@ -611,13 +609,18 @@ impl<'db> MirLowerCtx<'_, 'db> { if mode == MatchingMode::Check { let e = self.const_eval_discriminant(v)? as u128; let tmp = self.discr_temp_place(current); - self.push_assignment(current, tmp, Rvalue::Discriminant(cond_place), span); + self.push_assignment( + current, + tmp, + Rvalue::Discriminant(cond_place.store()), + span, + ); let next = self.new_basic_block(); let else_target = current_else.get_or_insert_with(|| self.new_basic_block()); self.set_terminator( current, TerminatorKind::SwitchInt { - discr: Operand { kind: OperandKind::Copy(tmp), span: None }, + discr: Operand { kind: OperandKind::Copy(tmp.store()), span: None }, targets: SwitchTargets::static_if(e, next, *else_target), }, span, @@ -656,7 +659,7 @@ impl<'db> MirLowerCtx<'_, 'db> { v: VariantId, current: BasicBlockId, current_else: Option<BasicBlockId>, - cond_place: &Place, + cond_place: &PlaceRef<'db>, mode: MatchingMode, ) -> Result<'db, (BasicBlockId, Option<BasicBlockId>)> { Ok(match shape { @@ -700,11 +703,11 @@ impl<'db> MirLowerCtx<'_, 'db> { mut current: BasicBlockId, mut current_else: Option<BasicBlockId>, args: impl Iterator<Item = (PlaceElem, PatId)>, - cond_place: &Place, + cond_place: &PlaceRef<'db>, mode: MatchingMode, ) -> Result<'db, (BasicBlockId, Option<BasicBlockId>)> { for (proj, arg) in args { - let cond_place = cond_place.project(proj, &mut self.result.projection_store); + let cond_place = cond_place.project(proj); (current, current_else) = self.pattern_match_inner(current, current_else, cond_place, arg, mode)?; } @@ -718,7 +721,7 @@ impl<'db> MirLowerCtx<'_, 'db> { args: &[PatId], ellipsis: Option<u32>, fields: impl DoubleEndedIterator<Item = PlaceElem> + Clone, - cond_place: &Place, + cond_place: &PlaceRef<'db>, mode: MatchingMode, ) -> Result<'db, (BasicBlockId, Option<BasicBlockId>)> { let (al, ar) = args.split_at(ellipsis.map_or(args.len(), |it| it as usize)); diff --git a/crates/hir-ty/src/mir/pretty.rs b/crates/hir-ty/src/mir/pretty.rs index a534e50997..9054987066 100644 --- a/crates/hir-ty/src/mir/pretty.rs +++ b/crates/hir-ty/src/mir/pretty.rs @@ -373,7 +373,7 @@ impl<'a, 'db> MirPrettyCtx<'a, 'db> { } } } - f(self, p.local, p.projection.lookup(&self.body.projection_store)); + f(self, p.local, p.projection.lookup()); } fn operand(&mut self, r: &Operand) { diff --git a/crates/hir-ty/src/next_solver.rs b/crates/hir-ty/src/next_solver.rs index 47b4b1dc4a..f0d33ad2dd 100644 --- a/crates/hir-ty/src/next_solver.rs +++ b/crates/hir-ty/src/next_solver.rs @@ -120,6 +120,7 @@ pub struct DefaultEmpty<'db> { pub clauses: Clauses<'db>, pub region_assumptions: RegionAssumptions<'db>, pub consts: Consts<'db>, + pub projection: crate::mir::Projection<'db>, } pub struct DefaultAny<'db> { @@ -237,6 +238,12 @@ pub fn default_types<'a, 'db>(db: &'db dyn HirDatabase) -> &'a DefaultAny<'db> { let ty = ManuallyDrop::new(ty.store()); ty.as_ref() }; + let create_projection = |slice| { + let it = crate::mir::Projection::new_from_slice(slice); + // We need to increase the refcount (forever), so that the types won't be freed. + let it = ManuallyDrop::new(it.store()); + it.as_ref() + }; let str = create_ty(TyKind::Str); let statik = create_region(RegionKind::ReStatic); @@ -303,6 +310,7 @@ pub fn default_types<'a, 'db>(db: &'db dyn HirDatabase) -> &'a DefaultAny<'db> { clauses: create_clauses(&[]), region_assumptions: create_region_assumptions(&[]), consts: create_consts(&[]), + projection: create_projection(&[]), }, one_invariant: create_variances_of(&[rustc_type_ir::Variance::Invariant]), one_covariant: create_variances_of(&[rustc_type_ir::Variance::Covariant]), diff --git a/crates/hir-ty/src/next_solver/interner.rs b/crates/hir-ty/src/next_solver/interner.rs index 5ca0e67d29..172b1a245f 100644 --- a/crates/hir-ty/src/next_solver/interner.rs +++ b/crates/hir-ty/src/next_solver/interner.rs @@ -2582,6 +2582,7 @@ pub unsafe fn collect_ty_garbage() { gc.add_slice_storage::<super::predicate::BoundExistentialPredicatesStorage>(); gc.add_slice_storage::<super::region::RegionAssumptionsStorage>(); gc.add_slice_storage::<super::ty::TysStorage>(); + gc.add_slice_storage::<crate::mir::ProjectionStorage>(); // SAFETY: // - By our precondition, there are no unrecorded types. @@ -2646,4 +2647,5 @@ impl_gc_visit_slice!( super::region::RegionAssumptionsStorage, super::ty::TysStorage, super::consts::ConstsStorage, + crate::mir::ProjectionStorage, ); diff --git a/crates/ide/src/inlay_hints/implicit_drop.rs b/crates/ide/src/inlay_hints/implicit_drop.rs index 57aba51b4e..f6b13cbe0b 100644 --- a/crates/ide/src/inlay_hints/implicit_drop.rs +++ b/crates/ide/src/inlay_hints/implicit_drop.rs @@ -43,7 +43,7 @@ pub(super) fn hints( for (_, bb) in mir.basic_blocks.iter() { let terminator = bb.terminator.as_ref()?; - if let TerminatorKind::Drop { place, .. } = terminator.kind { + if let TerminatorKind::Drop { place, .. } = &terminator.kind { if !place.projection.is_empty() { continue; // Ignore complex cases for now } |