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