1use 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 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 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 *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 *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 *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 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}