Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/mir.rs')
| -rw-r--r-- | crates/hir-ty/src/mir.rs | 402 |
1 files changed, 204 insertions, 198 deletions
diff --git a/crates/hir-ty/src/mir.rs b/crates/hir-ty/src/mir.rs index 482b420279..7aebe17e5b 100644 --- a/crates/hir-ty/src/mir.rs +++ b/crates/hir-ty/src/mir.rs @@ -2,18 +2,7 @@ use std::{collections::hash_map::Entry, fmt::Display, iter}; -use crate::{ - CallableDefId, ClosureId, Const, ConstScalar, InferenceResult, Interner, MemoryMap, - Substitution, TraitEnvironment, Ty, TyExt, TyKind, - consteval::usize_const, - db::HirDatabase, - display::{DisplayTarget, HirDisplay}, - infer::{PointerCast, normalize}, - lang_items::is_box, - mapping::ToChalk, -}; use base_db::Crate; -use chalk_ir::Mutability; use either::Either; use hir_def::{ DefWithBodyId, FieldId, StaticId, TupleFieldId, UnionId, VariantId, @@ -21,6 +10,25 @@ use hir_def::{ hir::{BindingAnnotation, BindingId, Expr, ExprId, Ordering, PatId}, }; use la_arena::{Arena, ArenaMap, Idx, RawIdx}; +use rustc_ast_ir::Mutability; +use rustc_hash::FxHashMap; +use rustc_type_ir::inherent::{AdtDef, GenericArgs as _, IntoKind, SliceLike, Ty as _}; +use smallvec::{SmallVec, smallvec}; +use stdx::{impl_from, never}; + +use crate::{ + CallableDefId, InferenceResult, MemoryMap, + consteval::usize_const, + db::{HirDatabase, InternedClosureId}, + display::{DisplayTarget, HirDisplay}, + infer::PointerCast, + lang_items::is_box, + next_solver::{ + Const, DbInterner, ErrorGuaranteed, GenericArgs, ParamEnv, Ty, TyKind, + infer::{InferCtxt, traits::ObligationCause}, + obligation_ctxt::ObligationCtxt, + }, +}; mod borrowck; mod eval; @@ -34,28 +42,24 @@ pub use eval::{ }; pub use lower::{MirLowerError, lower_to_mir, mir_body_for_closure_query, mir_body_query}; pub use monomorphization::{ - monomorphize_mir_body_bad, monomorphized_mir_body_for_closure_query, - monomorphized_mir_body_query, + monomorphized_mir_body_for_closure_query, monomorphized_mir_body_query, }; -use rustc_hash::FxHashMap; -use smallvec::{SmallVec, smallvec}; -use stdx::{impl_from, never}; pub(crate) use lower::mir_body_cycle_result; pub(crate) use monomorphization::monomorphized_mir_body_cycle_result; -use super::consteval::{intern_const_scalar, try_const_usize}; +use super::consteval::try_const_usize; -pub type BasicBlockId = Idx<BasicBlock>; -pub type LocalId = Idx<Local>; +pub type BasicBlockId<'db> = Idx<BasicBlock<'db>>; +pub type LocalId<'db> = Idx<Local<'db>>; -fn return_slot() -> LocalId { +fn return_slot<'db>() -> LocalId<'db> { LocalId::from_raw(RawIdx::from(0)) } #[derive(Debug, Clone, PartialEq, Eq)] -pub struct Local { - pub ty: Ty, +pub struct Local<'db> { + pub ty: Ty<'db>, } /// An operand in MIR represents a "value" in Rust, the definition of which is undecided and part of @@ -77,19 +81,19 @@ pub struct Local { /// currently implements it, but it seems like this may be something to check against in the /// validator. #[derive(Debug, PartialEq, Eq, Clone)] -pub struct Operand { - kind: OperandKind, +pub struct Operand<'db> { + kind: OperandKind<'db>, // FIXME : This should actually just be of type `MirSpan`. span: Option<MirSpan>, } #[derive(Debug, PartialEq, Eq, Clone)] -pub enum OperandKind { +pub enum OperandKind<'db> { /// Creates a value by loading the given place. /// /// Before drop elaboration, the type of the place must be `Copy`. After drop elaboration there /// is no such requirement. - Copy(Place), + Copy(Place<'db>), /// Creates a value by performing loading the place, just like the `Copy` operand. /// @@ -98,41 +102,41 @@ pub enum OperandKind { /// place without first re-initializing it. /// /// [UCG#188]: https://github.com/rust-lang/unsafe-code-guidelines/issues/188 - Move(Place), + Move(Place<'db>), /// Constants are already semantically values, and remain unchanged. - Constant(Const), + Constant { konst: Const<'db>, ty: Ty<'db> }, /// NON STANDARD: This kind of operand returns an immutable reference to that static memory. Rustc /// handles it with the `Constant` variant somehow. Static(StaticId), } -impl Operand { - fn from_concrete_const(data: Box<[u8]>, memory_map: MemoryMap, ty: Ty) -> Self { +impl<'db> Operand<'db> { + fn from_concrete_const(data: Box<[u8]>, memory_map: MemoryMap<'db>, ty: Ty<'db>) -> Self { + let interner = DbInterner::conjure(); Operand { - kind: OperandKind::Constant(intern_const_scalar( - ConstScalar::Bytes(data, memory_map), + kind: OperandKind::Constant { + konst: Const::new_valtree(interner, ty, data, memory_map), ty, - )), + }, span: None, } } - fn from_bytes(data: Box<[u8]>, ty: Ty) -> Self { + fn from_bytes(data: Box<[u8]>, ty: Ty<'db>) -> Self { Operand::from_concrete_const(data, MemoryMap::default(), ty) } - fn const_zst(ty: Ty) -> Operand { + fn const_zst(ty: Ty<'db>) -> Operand<'db> { Self::from_bytes(Box::default(), ty) } fn from_fn( - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, func_id: hir_def::FunctionId, - generic_args: Substitution, - ) -> Operand { - let ty = - chalk_ir::TyKind::FnDef(CallableDefId::FunctionId(func_id).to_chalk(db), generic_args) - .intern(Interner); + generic_args: GenericArgs<'db>, + ) -> Operand<'db> { + let interner = DbInterner::new_with(db, None, None); + let ty = Ty::new_fn_def(interner, CallableDefId::FunctionId(func_id).into(), generic_args); Operand::from_bytes(Box::default(), ty) } } @@ -151,83 +155,81 @@ pub enum ProjectionElem<V, T> { } impl<V, T> ProjectionElem<V, T> { - pub fn projected_ty( + pub fn projected_ty<'db>( &self, - mut base: Ty, - db: &dyn HirDatabase, - closure_field: impl FnOnce(ClosureId, &Substitution, usize) -> Ty, + infcx: &InferCtxt<'db>, + mut base: Ty<'db>, + closure_field: impl FnOnce(InternedClosureId, GenericArgs<'db>, usize) -> Ty<'db>, krate: Crate, - ) -> Ty { + ) -> Ty<'db> { + let interner = infcx.interner; + let db = interner.db; + // we only bail on mir building when there are type mismatches // but error types may pop up resulting in us still attempting to build the mir // so just propagate the error type - if base.is_unknown() { - return TyKind::Error.intern(Interner); + if base.is_ty_error() { + return Ty::new_error(interner, ErrorGuaranteed); } - if matches!(base.kind(Interner), TyKind::Alias(_) | TyKind::AssociatedType(..)) { - base = normalize( - db, - // FIXME: we should get this from caller - TraitEnvironment::empty(krate), - base, - ); + if matches!(base.kind(), TyKind::Alias(..)) { + let mut ocx = ObligationCtxt::new(infcx); + // FIXME: we should get this from caller + let env = ParamEnv::empty(); + match ocx.structurally_normalize_ty(&ObligationCause::dummy(), env, base) { + Ok(it) => base = it, + Err(_) => return Ty::new_error(interner, ErrorGuaranteed), + } } + match self { - ProjectionElem::Deref => match &base.kind(Interner) { - TyKind::Raw(_, inner) | TyKind::Ref(_, _, inner) => inner.clone(), - TyKind::Adt(adt, subst) if is_box(db, adt.0) => { - subst.at(Interner, 0).assert_ty_ref(Interner).clone() - } + ProjectionElem::Deref => match base.kind() { + TyKind::RawPtr(inner, _) | TyKind::Ref(_, inner, _) => inner, + TyKind::Adt(adt_def, subst) if is_box(db, adt_def.def_id().0) => subst.type_at(0), _ => { never!( "Overloaded deref on type {} is not a projection", base.display(db, DisplayTarget::from_crate(db, krate)) ); - TyKind::Error.intern(Interner) + Ty::new_error(interner, ErrorGuaranteed) } }, - ProjectionElem::Field(Either::Left(f)) => match base.kind(Interner) { + ProjectionElem::Field(Either::Left(f)) => match base.kind() { TyKind::Adt(_, subst) => { - db.field_types(f.parent)[f.local_id].clone().substitute(Interner, subst) + db.field_types(f.parent)[f.local_id].instantiate(interner, subst) } ty => { never!("Only adt has field, found {:?}", ty); - TyKind::Error.intern(Interner) + Ty::new_error(interner, ErrorGuaranteed) } }, - ProjectionElem::Field(Either::Right(f)) => match &base.kind(Interner) { - TyKind::Tuple(_, subst) => subst - .as_slice(Interner) - .get(f.index as usize) - .map(|x| x.assert_ty_ref(Interner)) - .cloned() - .unwrap_or_else(|| { + ProjectionElem::Field(Either::Right(f)) => match base.kind() { + TyKind::Tuple(subst) => { + subst.as_slice().get(f.index as usize).copied().unwrap_or_else(|| { never!("Out of bound tuple field"); - TyKind::Error.intern(Interner) - }), + Ty::new_error(interner, ErrorGuaranteed) + }) + } ty => { never!("Only tuple has tuple field: {:?}", ty); - TyKind::Error.intern(Interner) + Ty::new_error(interner, ErrorGuaranteed) } }, - ProjectionElem::ClosureField(f) => match &base.kind(Interner) { - TyKind::Closure(id, subst) => closure_field(*id, subst, *f), + ProjectionElem::ClosureField(f) => match base.kind() { + TyKind::Closure(id, subst) => closure_field(id.0, subst, *f), _ => { never!("Only closure has closure field"); - TyKind::Error.intern(Interner) + Ty::new_error(interner, ErrorGuaranteed) } }, - ProjectionElem::ConstantIndex { .. } | ProjectionElem::Index(_) => { - match &base.kind(Interner) { - TyKind::Array(inner, _) | TyKind::Slice(inner) => inner.clone(), - _ => { - never!("Overloaded index is not a projection"); - TyKind::Error.intern(Interner) - } + ProjectionElem::ConstantIndex { .. } | ProjectionElem::Index(_) => match base.kind() { + TyKind::Array(inner, _) | TyKind::Slice(inner) => inner, + _ => { + never!("Overloaded index is not a projection"); + Ty::new_error(interner, ErrorGuaranteed) } - } - &ProjectionElem::Subslice { from, to } => match &base.kind(Interner) { + }, + &ProjectionElem::Subslice { from, to } => match base.kind() { TyKind::Array(inner, c) => { let next_c = usize_const( db, @@ -237,34 +239,34 @@ impl<V, T> ProjectionElem<V, T> { }, krate, ); - TyKind::Array(inner.clone(), next_c).intern(Interner) + Ty::new_array_with_const_len(interner, inner, next_c) } - TyKind::Slice(_) => base.clone(), + TyKind::Slice(_) => base, _ => { never!("Subslice projection should only happen on slice and array"); - TyKind::Error.intern(Interner) + Ty::new_error(interner, ErrorGuaranteed) } }, ProjectionElem::OpaqueCast(_) => { never!("We don't emit these yet"); - TyKind::Error.intern(Interner) + Ty::new_error(interner, ErrorGuaranteed) } } } } -type PlaceElem = ProjectionElem<LocalId, Ty>; +type PlaceElem<'db> = ProjectionElem<LocalId<'db>, Ty<'db>>; #[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>, +pub struct ProjectionStore<'db> { + id_to_proj: FxHashMap<ProjectionId, Box<[PlaceElem<'db>]>>, + proj_to_id: FxHashMap<Box<[PlaceElem<'db>]>, ProjectionId>, } -impl Default for ProjectionStore { +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` @@ -273,17 +275,17 @@ impl Default for ProjectionStore { } } -impl ProjectionStore { +impl<'db> ProjectionStore<'db> { pub fn shrink_to_fit(&mut self) { self.id_to_proj.shrink_to_fit(); self.proj_to_id.shrink_to_fit(); } - pub fn intern_if_exist(&self, projection: &[PlaceElem]) -> Option<ProjectionId> { + pub fn intern_if_exist(&self, projection: &[PlaceElem<'db>]) -> Option<ProjectionId> { self.proj_to_id.get(projection).copied() } - pub fn intern(&mut self, projection: Box<[PlaceElem]>) -> ProjectionId { + pub fn intern(&mut self, projection: Box<[PlaceElem<'db>]>) -> ProjectionId { let new_id = ProjectionId(self.proj_to_id.len() as u32); match self.proj_to_id.entry(projection) { Entry::Occupied(id) => *id.get(), @@ -304,11 +306,15 @@ impl ProjectionId { self == ProjectionId::EMPTY } - pub fn lookup(self, store: &ProjectionStore) -> &[PlaceElem] { + pub fn lookup<'a, 'db>(self, store: &'a ProjectionStore<'db>) -> &'a [PlaceElem<'db>] { store.id_to_proj.get(&self).unwrap() } - pub fn project(self, projection: PlaceElem, store: &mut ProjectionStore) -> ProjectionId { + pub fn project<'db>( + self, + projection: PlaceElem<'db>, + store: &mut ProjectionStore<'db>, + ) -> ProjectionId { let mut current = self.lookup(store).to_vec(); current.push(projection); store.intern(current.into()) @@ -316,13 +322,13 @@ impl ProjectionId { } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct Place { - pub local: LocalId, +pub struct Place<'db> { + pub local: LocalId<'db>, pub projection: ProjectionId, } -impl Place { - fn is_parent(&self, child: &Place, store: &ProjectionStore) -> bool { +impl<'db> Place<'db> { + fn is_parent(&self, child: &Place<'db>, store: &ProjectionStore<'db>) -> bool { self.local == child.local && child.projection.lookup(store).starts_with(self.projection.lookup(store)) } @@ -330,39 +336,39 @@ impl Place { /// The place itself is not included fn iterate_over_parents<'a>( &'a self, - store: &'a ProjectionStore, - ) -> impl Iterator<Item = Place> + 'a { + store: &'a ProjectionStore<'db>, + ) -> impl Iterator<Item = Place<'db>> + '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, store: &mut ProjectionStore) -> Place { + fn project(&self, projection: PlaceElem<'db>, store: &mut ProjectionStore<'db>) -> Place<'db> { Place { local: self.local, projection: self.projection.project(projection, store) } } } -impl From<LocalId> for Place { - fn from(local: LocalId) -> Self { +impl<'db> From<LocalId<'db>> for Place<'db> { + fn from(local: LocalId<'db>) -> Self { Self { local, projection: ProjectionId::EMPTY } } } #[derive(Debug, PartialEq, Eq, Clone)] -pub enum AggregateKind { +pub enum AggregateKind<'db> { /// The type is of the element - Array(Ty), + Array(Ty<'db>), /// The type is of the tuple - Tuple(Ty), - Adt(VariantId, Substitution), + Tuple(Ty<'db>), + Adt(VariantId, GenericArgs<'db>), Union(UnionId, FieldId), - Closure(Ty), + Closure(Ty<'db>), //Coroutine(LocalDefId, SubstsRef, Movability), } #[derive(Debug, Clone, Hash, PartialEq, Eq)] -pub struct SwitchTargets { +pub struct SwitchTargets<'db> { /// Possible values. The locations to branch to in each case /// are found in the corresponding indices from the `targets` vector. values: SmallVec<[u128; 1]>, @@ -379,17 +385,17 @@ pub struct SwitchTargets { // // However we’ve decided to keep this as-is until we figure a case // where some other approach seems to be strictly better than other. - targets: SmallVec<[BasicBlockId; 2]>, + targets: SmallVec<[BasicBlockId<'db>; 2]>, } -impl SwitchTargets { +impl<'db> SwitchTargets<'db> { /// Creates switch targets from an iterator of values and target blocks. /// /// The iterator may be empty, in which case the `SwitchInt` instruction is equivalent to /// `goto otherwise;`. pub fn new( - targets: impl Iterator<Item = (u128, BasicBlockId)>, - otherwise: BasicBlockId, + targets: impl Iterator<Item = (u128, BasicBlockId<'db>)>, + otherwise: BasicBlockId<'db>, ) -> Self { let (values, mut targets): (SmallVec<_>, SmallVec<_>) = targets.unzip(); targets.push(otherwise); @@ -398,12 +404,12 @@ impl SwitchTargets { /// Builds a switch targets definition that jumps to `then` if the tested value equals `value`, /// and to `else_` if not. - pub fn static_if(value: u128, then: BasicBlockId, else_: BasicBlockId) -> Self { + pub fn static_if(value: u128, then: BasicBlockId<'db>, else_: BasicBlockId<'db>) -> Self { Self { values: smallvec![value], targets: smallvec![then, else_] } } /// Returns the fallback target that is jumped to when none of the values match the operand. - pub fn otherwise(&self) -> BasicBlockId { + pub fn otherwise(&self) -> BasicBlockId<'db> { *self.targets.last().unwrap() } @@ -413,33 +419,33 @@ impl SwitchTargets { /// including the `otherwise` fallback target. /// /// Note that this may yield 0 elements. Only the `otherwise` branch is mandatory. - pub fn iter(&self) -> impl Iterator<Item = (u128, BasicBlockId)> + '_ { + pub fn iter(&self) -> impl Iterator<Item = (u128, BasicBlockId<'db>)> + '_ { iter::zip(&self.values, &self.targets).map(|(x, y)| (*x, *y)) } /// Returns a slice with all possible jump targets (including the fallback target). - pub fn all_targets(&self) -> &[BasicBlockId] { + pub fn all_targets(&self) -> &[BasicBlockId<'db>] { &self.targets } /// Finds the `BasicBlock` to which this `SwitchInt` will branch given the /// specific value. This cannot fail, as it'll return the `otherwise` /// branch if there's not a specific match for the value. - pub fn target_for_value(&self, value: u128) -> BasicBlockId { + pub fn target_for_value(&self, value: u128) -> BasicBlockId<'db> { self.iter().find_map(|(v, t)| (v == value).then_some(t)).unwrap_or_else(|| self.otherwise()) } } #[derive(Debug, PartialEq, Eq, Clone)] -pub struct Terminator { +pub struct Terminator<'db> { pub span: MirSpan, - pub kind: TerminatorKind, + pub kind: TerminatorKind<'db>, } #[derive(Debug, PartialEq, Eq, Clone)] -pub enum TerminatorKind { +pub enum TerminatorKind<'db> { /// Block has one successor; we continue execution there. - Goto { target: BasicBlockId }, + Goto { target: BasicBlockId<'db> }, /// Switches based on the computed value. /// @@ -451,9 +457,9 @@ pub enum TerminatorKind { /// Target values may not appear more than once. SwitchInt { /// The discriminant value being tested. - discr: Operand, + discr: Operand<'db>, - targets: SwitchTargets, + targets: SwitchTargets<'db>, }, /// Indicates that the landing pad is finished and that the process should continue unwinding. @@ -504,7 +510,7 @@ pub enum TerminatorKind { /// > The drop glue is executed if, among all statements executed within this `Body`, an assignment to /// > the place or one of its "parents" occurred more recently than a move out of it. This does not /// > consider indirect assignments. - Drop { place: Place, target: BasicBlockId, unwind: Option<BasicBlockId> }, + Drop { place: Place<'db>, target: BasicBlockId<'db>, unwind: Option<BasicBlockId<'db>> }, /// Drops the place and assigns a new value to it. /// @@ -537,10 +543,10 @@ pub enum TerminatorKind { /// /// Disallowed after drop elaboration. DropAndReplace { - place: Place, - value: Operand, - target: BasicBlockId, - unwind: Option<BasicBlockId>, + place: Place<'db>, + value: Operand<'db>, + target: BasicBlockId<'db>, + unwind: Option<BasicBlockId<'db>>, }, /// Roughly speaking, evaluates the `func` operand and the arguments, and starts execution of @@ -555,18 +561,18 @@ pub enum TerminatorKind { /// [#71117]: https://github.com/rust-lang/rust/issues/71117 Call { /// The function that’s being called. - func: Operand, + func: Operand<'db>, /// Arguments the function is called with. /// These are owned by the callee, which is free to modify them. /// This allows the memory occupied by "by-value" arguments to be /// reused across function calls without duplicating the contents. - args: Box<[Operand]>, + args: Box<[Operand<'db>]>, /// Where the returned value will be written - destination: Place, + destination: Place<'db>, /// Where to go after this call returns. If none, the call necessarily diverges. - target: Option<BasicBlockId>, + target: Option<BasicBlockId<'db>>, /// Cleanups to be done if the call unwinds. - cleanup: Option<BasicBlockId>, + cleanup: Option<BasicBlockId<'db>>, /// `true` if this is from a call in HIR rather than from an overloaded /// operator. True for overloaded function call. from_hir_call: bool, @@ -582,11 +588,11 @@ pub enum TerminatorKind { /// necessarily executed even in the case of a panic, for example in `-C panic=abort`. If the /// assertion does not fail, execution continues at the specified basic block. Assert { - cond: Operand, + cond: Operand<'db>, expected: bool, //msg: AssertMessage, - target: BasicBlockId, - cleanup: Option<BasicBlockId>, + target: BasicBlockId<'db>, + cleanup: Option<BasicBlockId<'db>>, }, /// Marks a suspend point. @@ -603,13 +609,13 @@ pub enum TerminatorKind { /// **Needs clarification**: What about the evaluation order of the `resume_arg` and `value`? Yield { /// The value to return. - value: Operand, + value: Operand<'db>, /// Where to resume to. - resume: BasicBlockId, + resume: BasicBlockId<'db>, /// The place to store the resume argument in. - resume_arg: Place, + resume_arg: Place<'db>, /// Cleanup to be done if the coroutine is dropped at this suspend point. - drop: Option<BasicBlockId>, + drop: Option<BasicBlockId<'db>>, }, /// Indicates the end of dropping a coroutine. @@ -632,10 +638,10 @@ pub enum TerminatorKind { /// Disallowed after drop elaboration. FalseEdge { /// The target normal control flow will take. - real_target: BasicBlockId, + real_target: BasicBlockId<'db>, /// A block control flow could conceptually jump to, but won't in /// practice. - imaginary_target: BasicBlockId, + imaginary_target: BasicBlockId<'db>, }, /// A terminator for blocks that only take one path in reality, but where we reserve the right @@ -647,14 +653,14 @@ pub enum TerminatorKind { /// Disallowed after drop elaboration. FalseUnwind { /// The target normal control flow will take. - real_target: BasicBlockId, + real_target: BasicBlockId<'db>, /// The imaginary cleanup block link. This particular path will never be taken /// in practice, but in order to avoid fragility we want to always /// consider it in borrowck. We don't want to accept programs which /// pass borrowck only when `panic=abort` or some assertions are disabled /// due to release vs. debug mode builds. This needs to be an `Option` because /// of the `remove_noop_landing_pads` and `abort_unwinding_calls` passes. - unwind: Option<BasicBlockId>, + unwind: Option<BasicBlockId<'db>>, }, } @@ -709,10 +715,10 @@ impl BorrowKind { } } - fn from_chalk(m: Mutability) -> Self { + fn from_rustc(m: rustc_ast_ir::Mutability) -> Self { match m { - Mutability::Not => BorrowKind::Shared, - Mutability::Mut => BorrowKind::Mut { kind: MutBorrowKind::Default }, + rustc_ast_ir::Mutability::Not => BorrowKind::Shared, + rustc_ast_ir::Mutability::Mut => BorrowKind::Mut { kind: MutBorrowKind::Default }, } } } @@ -841,8 +847,8 @@ impl From<hir_def::hir::CmpOp> for BinOp { } } -impl From<Operand> for Rvalue { - fn from(x: Operand) -> Self { +impl<'db> From<Operand<'db>> for Rvalue<'db> { + fn from(x: Operand<'db>) -> Self { Self::Use(x) } } @@ -871,14 +877,14 @@ pub enum CastKind { } #[derive(Debug, PartialEq, Eq, Clone)] -pub enum Rvalue { +pub enum Rvalue<'db> { /// Yields the operand unchanged - Use(Operand), + Use(Operand<'db>), /// Creates an array where each element is the value of the operand. /// /// Corresponds to source code like `[x; 32]`. - Repeat(Operand, Const), + Repeat(Operand<'db>, Const<'db>), /// Creates a reference of the indicated kind to the place. /// @@ -887,7 +893,7 @@ pub enum Rvalue { /// exactly what the behavior of this operation should be. /// /// `Shallow` borrows are disallowed after drop lowering. - Ref(BorrowKind, Place), + Ref(BorrowKind, Place<'db>), /// Creates a pointer/reference to the given thread local. /// @@ -918,7 +924,7 @@ pub enum Rvalue { /// If the type of the place is an array, this is the array length. For slices (`[T]`, not /// `&[T]`) this accesses the place's metadata to determine the length. This rvalue is /// ill-formed for places of other types. - Len(Place), + Len(Place<'db>), /// Performs essentially all of the casts that can be performed via `as`. /// @@ -926,7 +932,7 @@ pub enum Rvalue { /// /// **FIXME**: Document exactly which `CastKind`s allow which types of casts. Figure out why /// `ArrayToPointer` and `MutToConstPointer` are special. - Cast(CastKind, Operand, Ty), + Cast(CastKind, Operand<'db>, Ty<'db>), // FIXME link to `pointer::offset` when it hits stable. /// * `Offset` has the same semantics as `pointer::offset`, except that the second @@ -958,7 +964,7 @@ pub enum Rvalue { /// when the value of right-hand side is negative. /// /// Other combinations of types and operators are unsupported. - CheckedBinaryOp(BinOp, Operand, Operand), + CheckedBinaryOp(BinOp, Operand<'db>, Operand<'db>), /// Computes a value as described by the operation. //NullaryOp(NullOp, Ty), @@ -969,7 +975,7 @@ pub enum Rvalue { /// Also does two's-complement arithmetic. Negation requires a signed integer or a float; /// bitwise not requires a signed integer, unsigned integer, or bool. Both operation kinds /// return a value with the same type as their operand. - UnaryOp(UnOp, Operand), + UnaryOp(UnOp, Operand<'db>), /// Computes the discriminant of the place, returning it as an integer of type /// [`discriminant_ty`]. Returns zero for types without discriminant. @@ -981,7 +987,7 @@ pub enum Rvalue { /// [`discriminant_ty`]: crate::ty::Ty::discriminant_ty /// [#91095]: https://github.com/rust-lang/rust/issues/91095 /// [`discriminant_for_variant`]: crate::ty::Ty::discriminant_for_variant - Discriminant(Place), + Discriminant(Place<'db>), /// Creates an aggregate value, like a tuple or struct. /// @@ -991,17 +997,17 @@ pub enum Rvalue { /// /// Disallowed after deaggregation for all aggregate kinds except `Array` and `Coroutine`. After /// coroutine lowering, `Coroutine` aggregate kinds are disallowed too. - Aggregate(AggregateKind, Box<[Operand]>), + Aggregate(AggregateKind<'db>, Box<[Operand<'db>]>), /// Transmutes a `*mut u8` into shallow-initialized `Box<T>`. /// /// This is different from a normal transmute because dataflow analysis will treat the box as /// initialized but its content as uninitialized. Like other pointer casts, this in general /// affects alias analysis. - ShallowInitBox(Operand, Ty), + ShallowInitBox(Operand<'db>, Ty<'db>), /// NON STANDARD: allocates memory with the type's layout, and shallow init the box with the resulting pointer. - ShallowInitBoxWithAlloc(Ty), + ShallowInitBoxWithAlloc(Ty<'db>), /// A CopyForDeref is equivalent to a read from a place at the /// codegen level, but is treated specially by drop elaboration. When such a read happens, it @@ -1011,41 +1017,41 @@ pub enum Rvalue { /// read never happened and just projects further. This allows simplifying various MIR /// optimizations and codegen backends that previously had to handle deref operations anywhere /// in a place. - CopyForDeref(Place), + CopyForDeref(Place<'db>), } #[derive(Debug, PartialEq, Eq, Clone)] -pub enum StatementKind { - Assign(Place, Rvalue), - FakeRead(Place), +pub enum StatementKind<'db> { + Assign(Place<'db>, Rvalue<'db>), + FakeRead(Place<'db>), //SetDiscriminant { // place: Box<Place>, // variant_index: VariantIdx, //}, - Deinit(Place), - StorageLive(LocalId), - StorageDead(LocalId), + Deinit(Place<'db>), + StorageLive(LocalId<'db>), + StorageDead(LocalId<'db>), //Retag(RetagKind, Box<Place>), //AscribeUserType(Place, UserTypeProjection, Variance), //Intrinsic(Box<NonDivergingIntrinsic>), Nop, } -impl StatementKind { - fn with_span(self, span: MirSpan) -> Statement { +impl<'db> StatementKind<'db> { + fn with_span(self, span: MirSpan) -> Statement<'db> { Statement { kind: self, span } } } #[derive(Debug, PartialEq, Eq, Clone)] -pub struct Statement { - pub kind: StatementKind, +pub struct Statement<'db> { + pub kind: StatementKind<'db>, pub span: MirSpan, } #[derive(Debug, Default, Clone, PartialEq, Eq)] -pub struct BasicBlock { +pub struct BasicBlock<'db> { /// List of statements in this block. - pub statements: Vec<Statement>, + pub statements: Vec<Statement<'db>>, /// Terminator for this block. /// @@ -1055,7 +1061,7 @@ pub struct BasicBlock { /// exception is that certain passes, such as `simplify_cfg`, swap /// out the terminator temporarily with `None` while they continue /// to recurse over the set of basic blocks. - pub terminator: Option<Terminator>, + pub terminator: Option<Terminator<'db>>, /// If true, this block lies on an unwind path. This is used /// during codegen where distinct kinds of basic blocks may be @@ -1065,35 +1071,35 @@ 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, +pub struct MirBody<'db> { + pub projection_store: ProjectionStore<'db>, + pub basic_blocks: Arena<BasicBlock<'db>>, + pub locals: Arena<Local<'db>>, + pub start_block: BasicBlockId<'db>, pub owner: DefWithBodyId, - pub binding_locals: ArenaMap<BindingId, LocalId>, - pub param_locals: Vec<LocalId>, + pub binding_locals: ArenaMap<BindingId, LocalId<'db>>, + pub param_locals: Vec<LocalId<'db>>, /// This field stores the closures directly owned by this body. It is used /// in traversing every mir body. - pub closures: Vec<ClosureId>, + pub closures: Vec<InternedClosureId>, } -impl MirBody { - pub fn local_to_binding_map(&self) -> ArenaMap<LocalId, BindingId> { +impl<'db> MirBody<'db> { + pub fn local_to_binding_map(&self) -> ArenaMap<LocalId<'db>, BindingId> { 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<'db>, &mut ProjectionStore<'db>)) { + fn for_operand<'db>( + op: &mut Operand<'db>, + f: &mut impl FnMut(&mut Place<'db>, &mut ProjectionStore<'db>), + store: &mut ProjectionStore<'db>, ) { match &mut op.kind { OperandKind::Copy(p) | OperandKind::Move(p) => { f(p, store); } - OperandKind::Constant(_) | OperandKind::Static(_) => (), + OperandKind::Constant { .. } | OperandKind::Static(_) => (), } } for (_, block) in self.basic_blocks.iter_mut() { |