1use std::mem;
11
12use chalk_ir::{
13 ConstData, DebruijnIndex,
14 fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable},
15};
16use hir_def::DefWithBodyId;
17use triomphe::Arc;
18
19use crate::{
20 Const, Interner, ProjectionTy, Substitution, TraitEnvironment, Ty, TyKind,
21 consteval::{intern_const_scalar, unknown_const},
22 db::{HirDatabase, InternedClosure, InternedClosureId},
23 from_placeholder_idx,
24 generics::{Generics, generics},
25 infer::normalize,
26};
27
28use super::{MirBody, MirLowerError, Operand, OperandKind, Rvalue, StatementKind, TerminatorKind};
29
30macro_rules! not_supported {
31 ($it: expr) => {
32 return Err(MirLowerError::NotSupported(format!($it)))
33 };
34}
35
36struct Filler<'a> {
37 db: &'a dyn HirDatabase,
38 trait_env: Arc<TraitEnvironment>,
39 subst: &'a Substitution,
40 generics: Option<Generics>,
41 owner: DefWithBodyId,
42}
43impl FallibleTypeFolder<Interner> for Filler<'_> {
44 type Error = MirLowerError;
45
46 fn as_dyn(&mut self) -> &mut dyn FallibleTypeFolder<Interner, Error = Self::Error> {
47 self
48 }
49
50 fn interner(&self) -> Interner {
51 Interner
52 }
53
54 fn try_fold_ty(
55 &mut self,
56 ty: Ty,
57 outer_binder: DebruijnIndex,
58 ) -> std::result::Result<Ty, Self::Error> {
59 match ty.kind(Interner) {
60 TyKind::AssociatedType(id, subst) => {
61 Ok(TyKind::Alias(chalk_ir::AliasTy::Projection(ProjectionTy {
64 associated_ty_id: *id,
65 substitution: subst.clone().try_fold_with(self, outer_binder)?,
66 }))
67 .intern(Interner))
68 }
69 TyKind::OpaqueType(id, subst) => {
70 let impl_trait_id = self.db.lookup_intern_impl_trait_id((*id).into());
71 let subst = subst.clone().try_fold_with(self.as_dyn(), outer_binder)?;
72 match impl_trait_id {
73 crate::ImplTraitId::ReturnTypeImplTrait(func, idx) => {
74 let infer = self.db.infer(func.into());
75 let filler = &mut Filler {
76 db: self.db,
77 owner: self.owner,
78 trait_env: self.trait_env.clone(),
79 subst: &subst,
80 generics: Some(generics(self.db, func.into())),
81 };
82 filler.try_fold_ty(infer.type_of_rpit[idx].clone(), outer_binder)
83 }
84 crate::ImplTraitId::TypeAliasImplTrait(..) => {
85 not_supported!("type alias impl trait");
86 }
87 crate::ImplTraitId::AsyncBlockTypeImplTrait(_, _) => {
88 not_supported!("async block impl trait");
89 }
90 }
91 }
92 _ => ty.try_super_fold_with(self.as_dyn(), outer_binder),
93 }
94 }
95
96 fn try_fold_free_placeholder_const(
97 &mut self,
98 _ty: chalk_ir::Ty<Interner>,
99 idx: chalk_ir::PlaceholderIndex,
100 _outer_binder: DebruijnIndex,
101 ) -> std::result::Result<chalk_ir::Const<Interner>, Self::Error> {
102 let it = from_placeholder_idx(self.db, idx).0;
103 let Some(idx) = self.generics.as_ref().and_then(|g| g.type_or_const_param_idx(it)) else {
104 not_supported!("missing idx in generics");
105 };
106 Ok(self
107 .subst
108 .as_slice(Interner)
109 .get(idx)
110 .and_then(|it| it.constant(Interner))
111 .ok_or_else(|| MirLowerError::GenericArgNotProvided(it, self.subst.clone()))?
112 .clone())
113 }
114
115 fn try_fold_free_placeholder_ty(
116 &mut self,
117 idx: chalk_ir::PlaceholderIndex,
118 _outer_binder: DebruijnIndex,
119 ) -> std::result::Result<Ty, Self::Error> {
120 let it = from_placeholder_idx(self.db, idx).0;
121 let Some(idx) = self.generics.as_ref().and_then(|g| g.type_or_const_param_idx(it)) else {
122 not_supported!("missing idx in generics");
123 };
124 Ok(self
125 .subst
126 .as_slice(Interner)
127 .get(idx)
128 .and_then(|it| it.ty(Interner))
129 .ok_or_else(|| MirLowerError::GenericArgNotProvided(it, self.subst.clone()))?
130 .clone())
131 }
132
133 fn try_fold_const(
134 &mut self,
135 constant: chalk_ir::Const<Interner>,
136 outer_binder: DebruijnIndex,
137 ) -> Result<chalk_ir::Const<Interner>, Self::Error> {
138 let next_ty = normalize(
139 self.db,
140 self.trait_env.clone(),
141 constant.data(Interner).ty.clone().try_fold_with(self, outer_binder)?,
142 );
143 ConstData { ty: next_ty, value: constant.data(Interner).value.clone() }
144 .intern(Interner)
145 .try_super_fold_with(self, outer_binder)
146 }
147}
148
149impl Filler<'_> {
150 fn fill_ty(&mut self, ty: &mut Ty) -> Result<(), MirLowerError> {
151 let tmp = mem::replace(ty, TyKind::Error.intern(Interner));
152 *ty = normalize(
153 self.db,
154 self.trait_env.clone(),
155 tmp.try_fold_with(self, DebruijnIndex::INNERMOST)?,
156 );
157 Ok(())
158 }
159
160 fn fill_const(&mut self, c: &mut Const) -> Result<(), MirLowerError> {
161 let tmp = mem::replace(c, unknown_const(c.data(Interner).ty.clone()));
162 *c = tmp.try_fold_with(self, DebruijnIndex::INNERMOST)?;
163 Ok(())
164 }
165
166 fn fill_subst(&mut self, ty: &mut Substitution) -> Result<(), MirLowerError> {
167 let tmp = mem::replace(ty, Substitution::empty(Interner));
168 *ty = tmp.try_fold_with(self, DebruijnIndex::INNERMOST)?;
169 Ok(())
170 }
171
172 fn fill_operand(&mut self, op: &mut Operand) -> Result<(), MirLowerError> {
173 match &mut op.kind {
174 OperandKind::Constant(c) => {
175 match &c.data(Interner).value {
176 chalk_ir::ConstValue::BoundVar(b) => {
177 let resolved = self
178 .subst
179 .as_slice(Interner)
180 .get(b.index)
181 .ok_or_else(|| {
182 MirLowerError::GenericArgNotProvided(
183 self.generics
184 .as_ref()
185 .and_then(|it| it.iter().nth(b.index))
186 .and_then(|(id, _)| match id {
187 hir_def::GenericParamId::ConstParamId(id) => {
188 Some(hir_def::TypeOrConstParamId::from(id))
189 }
190 hir_def::GenericParamId::TypeParamId(id) => {
191 Some(hir_def::TypeOrConstParamId::from(id))
192 }
193 _ => None,
194 })
195 .unwrap(),
196 self.subst.clone(),
197 )
198 })?
199 .assert_const_ref(Interner);
200 *c = resolved.clone();
201 }
202 chalk_ir::ConstValue::InferenceVar(_)
203 | chalk_ir::ConstValue::Placeholder(_) => {}
204 chalk_ir::ConstValue::Concrete(cc) => match &cc.interned {
205 crate::ConstScalar::UnevaluatedConst(const_id, subst) => {
206 let mut subst = subst.clone();
207 self.fill_subst(&mut subst)?;
208 *c = intern_const_scalar(
209 crate::ConstScalar::UnevaluatedConst(*const_id, subst),
210 c.data(Interner).ty.clone(),
211 );
212 }
213 crate::ConstScalar::Bytes(_, _) | crate::ConstScalar::Unknown => (),
214 },
215 }
216 self.fill_const(c)?;
217 }
218 OperandKind::Copy(_) | OperandKind::Move(_) | OperandKind::Static(_) => (),
219 }
220 Ok(())
221 }
222
223 fn fill_body(&mut self, body: &mut MirBody) -> Result<(), MirLowerError> {
224 for (_, l) in body.locals.iter_mut() {
225 self.fill_ty(&mut l.ty)?;
226 }
227 for (_, bb) in body.basic_blocks.iter_mut() {
228 for statement in &mut bb.statements {
229 match &mut statement.kind {
230 StatementKind::Assign(_, r) => match r {
231 Rvalue::Aggregate(ak, ops) => {
232 for op in &mut **ops {
233 self.fill_operand(op)?;
234 }
235 match ak {
236 super::AggregateKind::Array(ty)
237 | super::AggregateKind::Tuple(ty)
238 | super::AggregateKind::Closure(ty) => self.fill_ty(ty)?,
239 super::AggregateKind::Adt(_, subst) => self.fill_subst(subst)?,
240 super::AggregateKind::Union(_, _) => (),
241 }
242 }
243 Rvalue::ShallowInitBox(_, ty) | Rvalue::ShallowInitBoxWithAlloc(ty) => {
244 self.fill_ty(ty)?;
245 }
246 Rvalue::Use(op) => {
247 self.fill_operand(op)?;
248 }
249 Rvalue::Repeat(op, len) => {
250 self.fill_operand(op)?;
251 self.fill_const(len)?;
252 }
253 Rvalue::Ref(_, _)
254 | Rvalue::Len(_)
255 | Rvalue::Cast(_, _, _)
256 | Rvalue::CheckedBinaryOp(_, _, _)
257 | Rvalue::UnaryOp(_, _)
258 | Rvalue::Discriminant(_)
259 | Rvalue::CopyForDeref(_) => (),
260 Rvalue::ThreadLocalRef(n)
261 | Rvalue::AddressOf(n)
262 | Rvalue::BinaryOp(n)
263 | Rvalue::NullaryOp(n) => match *n {},
264 },
265 StatementKind::Deinit(_)
266 | StatementKind::FakeRead(_)
267 | StatementKind::StorageLive(_)
268 | StatementKind::StorageDead(_)
269 | StatementKind::Nop => (),
270 }
271 }
272 if let Some(terminator) = &mut bb.terminator {
273 match &mut terminator.kind {
274 TerminatorKind::Call { func, args, .. } => {
275 self.fill_operand(func)?;
276 for op in &mut **args {
277 self.fill_operand(op)?;
278 }
279 }
280 TerminatorKind::SwitchInt { discr, .. } => {
281 self.fill_operand(discr)?;
282 }
283 TerminatorKind::Goto { .. }
284 | TerminatorKind::UnwindResume
285 | TerminatorKind::Abort
286 | TerminatorKind::Return
287 | TerminatorKind::Unreachable
288 | TerminatorKind::Drop { .. }
289 | TerminatorKind::DropAndReplace { .. }
290 | TerminatorKind::Assert { .. }
291 | TerminatorKind::Yield { .. }
292 | TerminatorKind::CoroutineDrop
293 | TerminatorKind::FalseEdge { .. }
294 | TerminatorKind::FalseUnwind { .. } => (),
295 }
296 }
297 }
298 Ok(())
299 }
300}
301
302pub fn monomorphized_mir_body_query(
303 db: &dyn HirDatabase,
304 owner: DefWithBodyId,
305 subst: Substitution,
306 trait_env: Arc<crate::TraitEnvironment>,
307) -> Result<Arc<MirBody>, MirLowerError> {
308 let generics = owner.as_generic_def_id(db).map(|g_def| generics(db, g_def));
309 let filler = &mut Filler { db, subst: &subst, trait_env, generics, owner };
310 let body = db.mir_body(owner)?;
311 let mut body = (*body).clone();
312 filler.fill_body(&mut body)?;
313 Ok(Arc::new(body))
314}
315
316pub(crate) fn monomorphized_mir_body_cycle_result(
317 _db: &dyn HirDatabase,
318 _: DefWithBodyId,
319 _: Substitution,
320 _: Arc<crate::TraitEnvironment>,
321) -> Result<Arc<MirBody>, MirLowerError> {
322 Err(MirLowerError::Loop)
323}
324
325pub fn monomorphized_mir_body_for_closure_query(
326 db: &dyn HirDatabase,
327 closure: InternedClosureId,
328 subst: Substitution,
329 trait_env: Arc<crate::TraitEnvironment>,
330) -> Result<Arc<MirBody>, MirLowerError> {
331 let InternedClosure(owner, _) = db.lookup_intern_closure(closure);
332 let generics = owner.as_generic_def_id(db).map(|g_def| generics(db, g_def));
333 let filler = &mut Filler { db, subst: &subst, trait_env, generics, owner };
334 let body = db.mir_body_for_closure(closure)?;
335 let mut body = (*body).clone();
336 filler.fill_body(&mut body)?;
337 Ok(Arc::new(body))
338}
339
340pub fn monomorphize_mir_body_bad(
342 db: &dyn HirDatabase,
343 mut body: MirBody,
344 subst: Substitution,
345 trait_env: Arc<crate::TraitEnvironment>,
346) -> Result<MirBody, MirLowerError> {
347 let owner = body.owner;
348 let generics = owner.as_generic_def_id(db).map(|g_def| generics(db, g_def));
349 let filler = &mut Filler { db, subst: &subst, trait_env, generics, owner };
350 filler.fill_body(&mut body)?;
351 Ok(body)
352}