hir_ty/mir/
monomorphization.rs

1//! Monomorphization of mir, which is used in mir interpreter and const eval.
2//!
3//! The job of monomorphization is:
4//! * Monomorphization. That is, replacing `Option<T>` with `Option<i32>` where `T:=i32` substitution
5//!   is provided
6//! * Normalizing types, for example replacing RPIT of other functions called in this body.
7//!
8//! So the monomorphization should be called even if the substitution is empty.
9
10use hir_def::DefWithBodyId;
11use rustc_type_ir::inherent::{IntoKind, SliceLike};
12use rustc_type_ir::{
13    FallibleTypeFolder, TypeFlags, TypeFoldable, TypeSuperFoldable, TypeVisitableExt,
14};
15use triomphe::Arc;
16
17use crate::{
18    ParamEnvAndCrate,
19    next_solver::{Const, ConstKind, Region, RegionKind},
20};
21use crate::{
22    db::{HirDatabase, InternedClosureId},
23    next_solver::{
24        DbInterner, GenericArgs, Ty, TyKind, TypingMode,
25        infer::{DbInternerInferExt, InferCtxt, traits::ObligationCause},
26        obligation_ctxt::ObligationCtxt,
27        references_non_lt_error,
28    },
29};
30
31use super::{MirBody, MirLowerError, Operand, OperandKind, Rvalue, StatementKind, TerminatorKind};
32
33struct Filler<'db> {
34    infcx: InferCtxt<'db>,
35    trait_env: ParamEnvAndCrate<'db>,
36    subst: GenericArgs<'db>,
37}
38
39impl<'db> FallibleTypeFolder<DbInterner<'db>> for Filler<'db> {
40    type Error = MirLowerError<'db>;
41
42    fn cx(&self) -> DbInterner<'db> {
43        self.infcx.interner
44    }
45
46    fn try_fold_ty(&mut self, ty: Ty<'db>) -> Result<Ty<'db>, Self::Error> {
47        if !ty.has_type_flags(TypeFlags::HAS_ALIAS | TypeFlags::HAS_PARAM) {
48            return Ok(ty);
49        }
50
51        match ty.kind() {
52            TyKind::Alias(..) => {
53                // First instantiate params.
54                let ty = ty.try_super_fold_with(self)?;
55
56                let mut ocx = ObligationCtxt::new(&self.infcx);
57                let ty = ocx
58                    .structurally_normalize_ty(
59                        &ObligationCause::dummy(),
60                        self.trait_env.param_env,
61                        ty,
62                    )
63                    .map_err(|_| MirLowerError::NotSupported("can't normalize alias".to_owned()))?;
64                ty.try_super_fold_with(self)
65            }
66            TyKind::Param(param) => Ok(self
67                .subst
68                .as_slice()
69                .get(param.index as usize)
70                .and_then(|arg| arg.ty())
71                .ok_or_else(|| {
72                    MirLowerError::GenericArgNotProvided(param.id.into(), self.subst)
73                })?),
74            _ => ty.try_super_fold_with(self),
75        }
76    }
77
78    fn try_fold_const(&mut self, ct: Const<'db>) -> Result<Const<'db>, Self::Error> {
79        let ConstKind::Param(param) = ct.kind() else {
80            return ct.try_super_fold_with(self);
81        };
82        self.subst
83            .as_slice()
84            .get(param.index as usize)
85            .and_then(|arg| arg.konst())
86            .ok_or_else(|| MirLowerError::GenericArgNotProvided(param.id.into(), self.subst))
87    }
88
89    fn try_fold_region(&mut self, region: Region<'db>) -> Result<Region<'db>, Self::Error> {
90        let RegionKind::ReEarlyParam(param) = region.kind() else {
91            return Ok(region);
92        };
93        self.subst
94            .as_slice()
95            .get(param.index as usize)
96            .and_then(|arg| arg.region())
97            .ok_or_else(|| MirLowerError::GenericArgNotProvided(param.id.into(), self.subst))
98    }
99}
100
101impl<'db> Filler<'db> {
102    fn new(db: &'db dyn HirDatabase, env: ParamEnvAndCrate<'db>, subst: GenericArgs<'db>) -> Self {
103        let interner = DbInterner::new_with(db, env.krate);
104        let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis);
105        Self { infcx, trait_env: env, subst }
106    }
107
108    fn fill<T: TypeFoldable<DbInterner<'db>> + Copy>(
109        &mut self,
110        t: &mut T,
111    ) -> Result<(), MirLowerError<'db>> {
112        // Can't deep normalized as that'll try to normalize consts and fail.
113        *t = t.try_fold_with(self)?;
114        if references_non_lt_error(t) {
115            Err(MirLowerError::NotSupported("monomorphization resulted in errors".to_owned()))
116        } else {
117            Ok(())
118        }
119    }
120
121    fn fill_operand(&mut self, op: &mut Operand<'db>) -> Result<(), MirLowerError<'db>> {
122        match &mut op.kind {
123            OperandKind::Constant { konst, ty } => {
124                self.fill(konst)?;
125                self.fill(ty)?;
126            }
127            OperandKind::Copy(_) | OperandKind::Move(_) | OperandKind::Static(_) => (),
128        }
129        Ok(())
130    }
131
132    fn fill_body(&mut self, body: &mut MirBody<'db>) -> Result<(), MirLowerError<'db>> {
133        for (_, l) in body.locals.iter_mut() {
134            self.fill(&mut l.ty)?;
135        }
136        for (_, bb) in body.basic_blocks.iter_mut() {
137            for statement in &mut bb.statements {
138                match &mut statement.kind {
139                    StatementKind::Assign(_, r) => match r {
140                        Rvalue::Aggregate(ak, ops) => {
141                            for op in &mut **ops {
142                                self.fill_operand(op)?;
143                            }
144                            match ak {
145                                super::AggregateKind::Array(ty)
146                                | super::AggregateKind::Tuple(ty)
147                                | super::AggregateKind::Closure(ty) => self.fill(ty)?,
148                                super::AggregateKind::Adt(_, subst) => self.fill(subst)?,
149                                super::AggregateKind::Union(_, _) => (),
150                            }
151                        }
152                        Rvalue::ShallowInitBox(_, ty) | Rvalue::ShallowInitBoxWithAlloc(ty) => {
153                            self.fill(ty)?;
154                        }
155                        Rvalue::Use(op) => {
156                            self.fill_operand(op)?;
157                        }
158                        Rvalue::Repeat(op, len) => {
159                            self.fill_operand(op)?;
160                            self.fill(len)?;
161                        }
162                        Rvalue::Ref(_, _)
163                        | Rvalue::Len(_)
164                        | Rvalue::Cast(_, _, _)
165                        | Rvalue::CheckedBinaryOp(_, _, _)
166                        | Rvalue::UnaryOp(_, _)
167                        | Rvalue::Discriminant(_)
168                        | Rvalue::CopyForDeref(_) => (),
169                        Rvalue::ThreadLocalRef(n)
170                        | Rvalue::AddressOf(n)
171                        | Rvalue::BinaryOp(n)
172                        | Rvalue::NullaryOp(n) => match *n {},
173                    },
174                    StatementKind::Deinit(_)
175                    | StatementKind::FakeRead(_)
176                    | StatementKind::StorageLive(_)
177                    | StatementKind::StorageDead(_)
178                    | StatementKind::Nop => (),
179                }
180            }
181            if let Some(terminator) = &mut bb.terminator {
182                match &mut terminator.kind {
183                    TerminatorKind::Call { func, args, .. } => {
184                        self.fill_operand(func)?;
185                        for op in &mut **args {
186                            self.fill_operand(op)?;
187                        }
188                    }
189                    TerminatorKind::SwitchInt { discr, .. } => {
190                        self.fill_operand(discr)?;
191                    }
192                    TerminatorKind::Goto { .. }
193                    | TerminatorKind::UnwindResume
194                    | TerminatorKind::Abort
195                    | TerminatorKind::Return
196                    | TerminatorKind::Unreachable
197                    | TerminatorKind::Drop { .. }
198                    | TerminatorKind::DropAndReplace { .. }
199                    | TerminatorKind::Assert { .. }
200                    | TerminatorKind::Yield { .. }
201                    | TerminatorKind::CoroutineDrop
202                    | TerminatorKind::FalseEdge { .. }
203                    | TerminatorKind::FalseUnwind { .. } => (),
204                }
205            }
206        }
207        Ok(())
208    }
209}
210
211pub fn monomorphized_mir_body_query<'db>(
212    db: &'db dyn HirDatabase,
213    owner: DefWithBodyId,
214    subst: GenericArgs<'db>,
215    trait_env: ParamEnvAndCrate<'db>,
216) -> Result<Arc<MirBody<'db>>, MirLowerError<'db>> {
217    let mut filler = Filler::new(db, trait_env, subst);
218    let body = db.mir_body(owner)?;
219    let mut body = (*body).clone();
220    filler.fill_body(&mut body)?;
221    Ok(Arc::new(body))
222}
223
224pub(crate) fn monomorphized_mir_body_cycle_result<'db>(
225    _db: &'db dyn HirDatabase,
226    _: DefWithBodyId,
227    _: GenericArgs<'db>,
228    _: ParamEnvAndCrate<'db>,
229) -> Result<Arc<MirBody<'db>>, MirLowerError<'db>> {
230    Err(MirLowerError::Loop)
231}
232
233pub fn monomorphized_mir_body_for_closure_query<'db>(
234    db: &'db dyn HirDatabase,
235    closure: InternedClosureId,
236    subst: GenericArgs<'db>,
237    trait_env: ParamEnvAndCrate<'db>,
238) -> Result<Arc<MirBody<'db>>, MirLowerError<'db>> {
239    let mut filler = Filler::new(db, trait_env, subst);
240    let body = db.mir_body_for_closure(closure)?;
241    let mut body = (*body).clone();
242    filler.fill_body(&mut body)?;
243    Ok(Arc::new(body))
244}