Skip to main content

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 rustc_type_ir::inherent::IntoKind;
11use rustc_type_ir::{
12    FallibleTypeFolder, TypeFlags, TypeFoldable, TypeSuperFoldable, TypeVisitableExt,
13};
14
15use crate::{
16    InferBodyId, ParamEnvAndCrate,
17    next_solver::{
18        Allocation, AllocationData, Const, ConstKind, Region, RegionKind, StoredConst,
19        StoredGenericArgs, StoredTy,
20    },
21    traits::StoredParamEnvAndCrate,
22};
23use crate::{
24    db::{HirDatabase, InternedClosureId},
25    next_solver::{
26        DbInterner, GenericArgs, Ty, TyKind, TypingMode,
27        infer::{DbInternerInferExt, InferCtxt, traits::ObligationCause},
28        obligation_ctxt::ObligationCtxt,
29        references_non_lt_error,
30    },
31};
32
33use super::{MirBody, MirLowerError, Operand, OperandKind, Rvalue, StatementKind, TerminatorKind};
34
35struct Filler<'db> {
36    infcx: InferCtxt<'db>,
37    trait_env: ParamEnvAndCrate<'db>,
38    subst: GenericArgs<'db>,
39}
40
41impl<'db> FallibleTypeFolder<DbInterner<'db>> for Filler<'db> {
42    type Error = MirLowerError<'db>;
43
44    fn cx(&self) -> DbInterner<'db> {
45        self.infcx.interner
46    }
47
48    fn try_fold_ty(&mut self, ty: Ty<'db>) -> Result<Ty<'db>, Self::Error> {
49        if !ty.has_type_flags(TypeFlags::HAS_ALIAS | TypeFlags::HAS_PARAM) {
50            return Ok(ty);
51        }
52
53        match ty.kind() {
54            TyKind::Alias(..) => {
55                // First instantiate params.
56                let ty = ty.try_super_fold_with(self)?;
57
58                let mut ocx = ObligationCtxt::new(&self.infcx);
59                let ty = ocx
60                    .structurally_normalize_ty(
61                        &ObligationCause::dummy(),
62                        self.trait_env.param_env,
63                        ty,
64                    )
65                    .map_err(|_| MirLowerError::NotSupported("can't normalize alias".to_owned()))?;
66                // Normalization could introduce infer vars (for example, if the alias cannot be normalized),
67                // and we must not have infer vars in the body.
68                let ty = ty.replace_infer_with_error(self.infcx.interner);
69                ty.try_super_fold_with(self)
70            }
71            TyKind::Param(param) => Ok(self
72                .subst
73                .as_slice()
74                .get(param.index as usize)
75                .and_then(|arg| arg.ty())
76                .ok_or_else(|| {
77                    MirLowerError::GenericArgNotProvided(param.id.into(), self.subst.store())
78                })?),
79            _ => ty.try_super_fold_with(self),
80        }
81    }
82
83    fn try_fold_const(&mut self, ct: Const<'db>) -> Result<Const<'db>, Self::Error> {
84        let ConstKind::Param(param) = ct.kind() else {
85            return ct.try_super_fold_with(self);
86        };
87        self.subst.as_slice().get(param.index as usize).and_then(|arg| arg.konst()).ok_or_else(
88            || MirLowerError::GenericArgNotProvided(param.id.into(), self.subst.store()),
89        )
90    }
91
92    fn try_fold_region(&mut self, region: Region<'db>) -> Result<Region<'db>, Self::Error> {
93        let RegionKind::ReEarlyParam(param) = region.kind() else {
94            return Ok(region);
95        };
96        self.subst.as_slice().get(param.index as usize).and_then(|arg| arg.region()).ok_or_else(
97            || MirLowerError::GenericArgNotProvided(param.id.into(), self.subst.store()),
98        )
99    }
100}
101
102impl<'db> Filler<'db> {
103    fn new(db: &'db dyn HirDatabase, env: ParamEnvAndCrate<'db>, subst: GenericArgs<'db>) -> Self {
104        let interner = DbInterner::new_with(db, env.krate);
105        let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis);
106        Self { infcx, trait_env: env, subst }
107    }
108
109    fn fill_ty(&mut self, t: &mut StoredTy) -> Result<(), MirLowerError<'db>> {
110        // Can't deep normalized as that'll try to normalize consts and fail.
111        *t = t.as_ref().try_fold_with(self)?.store();
112        if references_non_lt_error(&t.as_ref()) {
113            Err(MirLowerError::NotSupported("monomorphization resulted in errors".to_owned()))
114        } else {
115            Ok(())
116        }
117    }
118
119    fn fill_const(&mut self, t: &mut StoredConst) -> Result<(), MirLowerError<'db>> {
120        // Can't deep normalized as that'll try to normalize consts and fail.
121        *t = t.as_ref().try_fold_with(self)?.store();
122        if references_non_lt_error(&t.as_ref()) {
123            Err(MirLowerError::NotSupported("monomorphization resulted in errors".to_owned()))
124        } else {
125            Ok(())
126        }
127    }
128
129    fn fill_args(&mut self, t: &mut StoredGenericArgs) -> Result<(), MirLowerError<'db>> {
130        // Can't deep normalized as that'll try to normalize consts and fail.
131        *t = t.as_ref().try_fold_with(self)?.store();
132        if references_non_lt_error(&t.as_ref()) {
133            Err(MirLowerError::NotSupported("monomorphization resulted in errors".to_owned()))
134        } else {
135            Ok(())
136        }
137    }
138
139    fn fill_operand(&mut self, op: &mut Operand) -> Result<(), MirLowerError<'db>> {
140        match &mut op.kind {
141            OperandKind::Constant { konst, ty } => {
142                self.fill_const(konst)?;
143                self.fill_ty(ty)?;
144            }
145            OperandKind::Allocation { allocation } => {
146                let alloc = allocation.as_ref();
147                let mut ty = alloc.ty.store();
148                self.fill_ty(&mut ty)?;
149                *allocation = Allocation::new(AllocationData {
150                    ty: ty.as_ref(),
151                    memory: alloc.memory.clone(),
152                    // FIXME: Do we need to fill the memory map too?
153                    memory_map: alloc.memory_map.clone(),
154                })
155                .store();
156            }
157            OperandKind::Copy(_) | OperandKind::Move(_) | OperandKind::Static(_) => (),
158        }
159        Ok(())
160    }
161
162    fn fill_body(&mut self, body: &mut MirBody<'db>) -> Result<(), MirLowerError<'db>> {
163        for (_, l) in body.locals.iter_mut() {
164            self.fill_ty(&mut l.ty)?;
165        }
166        for (_, bb) in body.basic_blocks.iter_mut() {
167            for statement in &mut bb.statements {
168                match &mut statement.kind {
169                    StatementKind::Assign(_, r) => match r {
170                        Rvalue::Aggregate(ak, ops) => {
171                            for op in &mut **ops {
172                                self.fill_operand(op)?;
173                            }
174                            match ak {
175                                super::AggregateKind::Array(ty)
176                                | super::AggregateKind::Tuple(ty)
177                                | super::AggregateKind::Closure(ty) => self.fill_ty(ty)?,
178                                super::AggregateKind::Adt(_, subst) => self.fill_args(subst)?,
179                                super::AggregateKind::Union(_, _) => (),
180                            }
181                        }
182                        Rvalue::ShallowInitBox(_, ty) | Rvalue::ShallowInitBoxWithAlloc(ty) => {
183                            self.fill_ty(ty)?;
184                        }
185                        Rvalue::Use(op) => {
186                            self.fill_operand(op)?;
187                        }
188                        Rvalue::Repeat(op, len) => {
189                            self.fill_operand(op)?;
190                            self.fill_const(len)?;
191                        }
192                        Rvalue::Ref(_, _)
193                        | Rvalue::Len(_)
194                        | Rvalue::Cast(_, _, _)
195                        | Rvalue::CheckedBinaryOp(_, _, _)
196                        | Rvalue::UnaryOp(_, _)
197                        | Rvalue::Discriminant(_)
198                        | Rvalue::CopyForDeref(_) => (),
199                        Rvalue::ThreadLocalRef(n)
200                        | Rvalue::AddressOf(n)
201                        | Rvalue::BinaryOp(n)
202                        | Rvalue::NullaryOp(n) => match *n {},
203                    },
204                    StatementKind::Deinit(_)
205                    | StatementKind::FakeRead(_)
206                    | StatementKind::StorageLive(_)
207                    | StatementKind::StorageDead(_)
208                    | StatementKind::Nop => (),
209                }
210            }
211            if let Some(terminator) = &mut bb.terminator {
212                match &mut terminator.kind {
213                    TerminatorKind::Call { func, args, .. } => {
214                        self.fill_operand(func)?;
215                        for op in &mut **args {
216                            self.fill_operand(op)?;
217                        }
218                    }
219                    TerminatorKind::SwitchInt { discr, .. } => {
220                        self.fill_operand(discr)?;
221                    }
222                    TerminatorKind::Goto { .. }
223                    | TerminatorKind::UnwindResume
224                    | TerminatorKind::Abort
225                    | TerminatorKind::Return
226                    | TerminatorKind::Unreachable
227                    | TerminatorKind::Drop { .. }
228                    | TerminatorKind::DropAndReplace { .. }
229                    | TerminatorKind::Assert { .. }
230                    | TerminatorKind::Yield { .. }
231                    | TerminatorKind::CoroutineDrop
232                    | TerminatorKind::FalseEdge { .. }
233                    | TerminatorKind::FalseUnwind { .. } => (),
234                }
235            }
236        }
237        Ok(())
238    }
239}
240
241#[salsa::tracked(returns(as_ref), cycle_result = monomorphized_mir_body_cycle_result)]
242pub fn monomorphized_mir_body_query<'db>(
243    db: &'db dyn HirDatabase,
244    owner: InferBodyId<'db>,
245    subst: StoredGenericArgs,
246    trait_env: StoredParamEnvAndCrate,
247) -> Result<MirBody<'db>, MirLowerError<'db>> {
248    let mut filler = Filler::new(db, trait_env.as_ref(db), subst.as_ref());
249    let body = db.mir_body(owner)?;
250    let mut body = (*body).clone();
251    filler.fill_body(&mut body)?;
252    Ok(body)
253}
254
255fn monomorphized_mir_body_cycle_result<'db>(
256    _db: &'db dyn HirDatabase,
257    _: salsa::Id,
258    _: InferBodyId<'db>,
259    _: StoredGenericArgs,
260    _: StoredParamEnvAndCrate,
261) -> Result<MirBody<'db>, MirLowerError<'db>> {
262    Err(MirLowerError::Loop)
263}
264
265#[salsa::tracked(returns(as_ref), cycle_result = monomorphized_mir_body_for_closure_cycle_result)]
266pub fn monomorphized_mir_body_for_closure_query<'db>(
267    db: &'db dyn HirDatabase,
268    closure: InternedClosureId<'db>,
269    subst: StoredGenericArgs,
270    trait_env: StoredParamEnvAndCrate,
271) -> Result<MirBody<'db>, MirLowerError<'db>> {
272    let mut filler = Filler::new(db, trait_env.as_ref(db), subst.as_ref());
273    let body = db.mir_body_for_closure(closure)?;
274    let mut body = (*body).clone();
275    filler.fill_body(&mut body)?;
276    Ok(body)
277}
278
279fn monomorphized_mir_body_for_closure_cycle_result<'db>(
280    _db: &'db dyn HirDatabase,
281    _: salsa::Id,
282    _: InternedClosureId<'db>,
283    _: StoredGenericArgs,
284    _: StoredParamEnvAndCrate,
285) -> Result<MirBody<'db>, MirLowerError<'db>> {
286    Err(MirLowerError::Loop)
287}