//! Monomorphization of mir, which is used in mir interpreter and const eval. //! //! The job of monomorphization is: //! * Monomorphization. That is, replacing `Option` with `Option` where `T:=i32` substitution //! is provided //! * Normalizing types, for example replacing RPIT of other functions called in this body. //! //! So the monomorphization should be called even if the substitution is empty. use hir_def::DefWithBodyId; use rustc_type_ir::inherent::IntoKind; use rustc_type_ir::{ FallibleTypeFolder, TypeFlags, TypeFoldable, TypeSuperFoldable, TypeVisitableExt, }; use triomphe::Arc; use crate::{ ParamEnvAndCrate, next_solver::{Const, ConstKind, Region, RegionKind, StoredConst, StoredGenericArgs, StoredTy}, traits::StoredParamEnvAndCrate, }; use crate::{ db::{HirDatabase, InternedClosureId}, next_solver::{ DbInterner, GenericArgs, Ty, TyKind, TypingMode, infer::{DbInternerInferExt, InferCtxt, traits::ObligationCause}, obligation_ctxt::ObligationCtxt, references_non_lt_error, }, }; use super::{MirBody, MirLowerError, Operand, OperandKind, Rvalue, StatementKind, TerminatorKind}; struct Filler<'db> { infcx: InferCtxt<'db>, trait_env: ParamEnvAndCrate<'db>, subst: GenericArgs<'db>, } impl<'db> FallibleTypeFolder> for Filler<'db> { type Error = MirLowerError; fn cx(&self) -> DbInterner<'db> { self.infcx.interner } fn try_fold_ty(&mut self, ty: Ty<'db>) -> Result, Self::Error> { if !ty.has_type_flags(TypeFlags::HAS_ALIAS | TypeFlags::HAS_PARAM) { return Ok(ty); } match ty.kind() { TyKind::Alias(..) => { // First instantiate params. let ty = ty.try_super_fold_with(self)?; let mut ocx = ObligationCtxt::new(&self.infcx); let ty = ocx .structurally_normalize_ty( &ObligationCause::dummy(), self.trait_env.param_env, ty, ) .map_err(|_| MirLowerError::NotSupported("can't normalize alias".to_owned()))?; ty.try_super_fold_with(self) } TyKind::Param(param) => Ok(self .subst .as_slice() .get(param.index as usize) .and_then(|arg| arg.ty()) .ok_or_else(|| { MirLowerError::GenericArgNotProvided(param.id.into(), self.subst.store()) })?), _ => ty.try_super_fold_with(self), } } fn try_fold_const(&mut self, ct: Const<'db>) -> Result, Self::Error> { let ConstKind::Param(param) = ct.kind() else { return ct.try_super_fold_with(self); }; self.subst.as_slice().get(param.index as usize).and_then(|arg| arg.konst()).ok_or_else( || MirLowerError::GenericArgNotProvided(param.id.into(), self.subst.store()), ) } fn try_fold_region(&mut self, region: Region<'db>) -> Result, Self::Error> { let RegionKind::ReEarlyParam(param) = region.kind() else { return Ok(region); }; self.subst.as_slice().get(param.index as usize).and_then(|arg| arg.region()).ok_or_else( || MirLowerError::GenericArgNotProvided(param.id.into(), self.subst.store()), ) } } impl<'db> Filler<'db> { fn new(db: &'db dyn HirDatabase, env: ParamEnvAndCrate<'db>, subst: GenericArgs<'db>) -> Self { let interner = DbInterner::new_with(db, env.krate); let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis); Self { infcx, trait_env: env, subst } } fn fill_ty(&mut self, t: &mut StoredTy) -> Result<(), MirLowerError> { // Can't deep normalized as that'll try to normalize consts and fail. *t = t.as_ref().try_fold_with(self)?.store(); if references_non_lt_error(&t.as_ref()) { Err(MirLowerError::NotSupported("monomorphization resulted in errors".to_owned())) } else { Ok(()) } } fn fill_const(&mut self, t: &mut StoredConst) -> Result<(), MirLowerError> { // Can't deep normalized as that'll try to normalize consts and fail. *t = t.as_ref().try_fold_with(self)?.store(); if references_non_lt_error(&t.as_ref()) { Err(MirLowerError::NotSupported("monomorphization resulted in errors".to_owned())) } else { Ok(()) } } fn fill_args(&mut self, t: &mut StoredGenericArgs) -> Result<(), MirLowerError> { // Can't deep normalized as that'll try to normalize consts and fail. *t = t.as_ref().try_fold_with(self)?.store(); if references_non_lt_error(&t.as_ref()) { Err(MirLowerError::NotSupported("monomorphization resulted in errors".to_owned())) } else { Ok(()) } } fn fill_operand(&mut self, op: &mut Operand) -> Result<(), MirLowerError> { match &mut op.kind { OperandKind::Constant { konst, ty } => { self.fill_const(konst)?; self.fill_ty(ty)?; } OperandKind::Copy(_) | OperandKind::Move(_) | OperandKind::Static(_) => (), } Ok(()) } fn fill_body(&mut self, body: &mut MirBody) -> Result<(), MirLowerError> { for (_, l) in body.locals.iter_mut() { self.fill_ty(&mut l.ty)?; } for (_, bb) in body.basic_blocks.iter_mut() { for statement in &mut bb.statements { match &mut statement.kind { StatementKind::Assign(_, r) => match r { Rvalue::Aggregate(ak, ops) => { for op in &mut **ops { self.fill_operand(op)?; } match ak { super::AggregateKind::Array(ty) | super::AggregateKind::Tuple(ty) | super::AggregateKind::Closure(ty) => self.fill_ty(ty)?, super::AggregateKind::Adt(_, subst) => self.fill_args(subst)?, super::AggregateKind::Union(_, _) => (), } } Rvalue::ShallowInitBox(_, ty) | Rvalue::ShallowInitBoxWithAlloc(ty) => { self.fill_ty(ty)?; } Rvalue::Use(op) => { self.fill_operand(op)?; } Rvalue::Repeat(op, len) => { self.fill_operand(op)?; self.fill_const(len)?; } Rvalue::Ref(_, _) | Rvalue::Len(_) | Rvalue::Cast(_, _, _) | Rvalue::CheckedBinaryOp(_, _, _) | Rvalue::UnaryOp(_, _) | Rvalue::Discriminant(_) | Rvalue::CopyForDeref(_) => (), Rvalue::ThreadLocalRef(n) | Rvalue::AddressOf(n) | Rvalue::BinaryOp(n) | Rvalue::NullaryOp(n) => match *n {}, }, StatementKind::Deinit(_) | StatementKind::FakeRead(_) | StatementKind::StorageLive(_) | StatementKind::StorageDead(_) | StatementKind::Nop => (), } } if let Some(terminator) = &mut bb.terminator { match &mut terminator.kind { TerminatorKind::Call { func, args, .. } => { self.fill_operand(func)?; for op in &mut **args { self.fill_operand(op)?; } } TerminatorKind::SwitchInt { discr, .. } => { self.fill_operand(discr)?; } TerminatorKind::Goto { .. } | TerminatorKind::UnwindResume | TerminatorKind::Abort | TerminatorKind::Return | TerminatorKind::Unreachable | TerminatorKind::Drop { .. } | TerminatorKind::DropAndReplace { .. } | TerminatorKind::Assert { .. } | TerminatorKind::Yield { .. } | TerminatorKind::CoroutineDrop | TerminatorKind::FalseEdge { .. } | TerminatorKind::FalseUnwind { .. } => (), } } } Ok(()) } } pub fn monomorphized_mir_body_query( db: &dyn HirDatabase, owner: DefWithBodyId, subst: StoredGenericArgs, trait_env: StoredParamEnvAndCrate, ) -> Result, MirLowerError> { let mut filler = Filler::new(db, trait_env.as_ref(), subst.as_ref()); let body = db.mir_body(owner)?; let mut body = (*body).clone(); filler.fill_body(&mut body)?; Ok(Arc::new(body)) } pub(crate) fn monomorphized_mir_body_cycle_result( _db: &dyn HirDatabase, _: salsa::Id, _: DefWithBodyId, _: StoredGenericArgs, _: StoredParamEnvAndCrate, ) -> Result, MirLowerError> { Err(MirLowerError::Loop) } pub fn monomorphized_mir_body_for_closure_query( db: &dyn HirDatabase, closure: InternedClosureId, subst: StoredGenericArgs, trait_env: StoredParamEnvAndCrate, ) -> Result, MirLowerError> { let mut filler = Filler::new(db, trait_env.as_ref(), subst.as_ref()); let body = db.mir_body_for_closure(closure)?; let mut body = (*body).clone(); filler.fill_body(&mut body)?; Ok(Arc::new(body)) }