charon_lib/transform/normalize/
partial_monomorphization.rs1use std::collections::{HashMap, HashSet, VecDeque};
14use std::fmt::Display;
15use std::mem;
16
17use derive_generic_visitor::Visitor;
18use index_vec::Idx;
19
20use crate::ast::types_utils::TyVisitable;
21use crate::ast::visitor::{VisitWithBinderDepth, VisitorWithBinderDepth};
22use crate::formatter::IntoFormatter;
23use crate::ids::IndexVec;
24use crate::options::MonomorphizeMut;
25use crate::pretty::FmtWithCtx;
26use crate::register_error;
27use crate::transform::ctx::TransformPass;
28use crate::{transform::TransformCtx, ullbc_ast::*};
29
30type MutabilityShape = Binder<GenericArgs>;
31
32#[derive(Visitor)]
34struct MutabilityShapeBuilder<'pm, 'ctx> {
35 pm: &'pm PartialMonomorphizer<'ctx>,
36 params: GenericParams,
38 extracted: GenericArgs,
40 binder_depth: DeBruijnId,
42}
43
44impl<'pm, 'ctx> MutabilityShapeBuilder<'pm, 'ctx> {
45 fn compute_shape(
66 pm: &'pm PartialMonomorphizer<'ctx>,
67 target_params: &GenericParams,
68 args: &GenericArgs,
69 ) -> (MutabilityShape, GenericArgs) {
70 let mut shape_contents = args.clone();
75 let mut builder = Self {
76 pm,
77 params: GenericParams {
78 regions: IndexVec::new(),
79 types: IndexVec::new(),
80 const_generics: IndexVec::new(),
81 ..target_params.clone()
82 },
83 extracted: GenericArgs {
84 regions: IndexVec::new(),
85 types: IndexVec::new(),
86 const_generics: IndexVec::new(),
87 trait_refs: mem::take(&mut shape_contents.trait_refs),
88 },
89 binder_depth: DeBruijnId::zero(),
90 };
91
92 let _ = VisitWithBinderDepth::new(&mut builder).visit(&mut shape_contents);
95
96 let shape_params = {
97 let mut shape_params = builder.params;
98 shape_params.trait_clauses = shape_params.trait_clauses.map_indexed(|i, x| {
102 if i.index() < target_params.trait_clauses.len() {
103 x.substitute_explicits(&shape_contents)
104 } else {
105 x
106 }
107 });
108 shape_params.trait_type_constraints =
109 shape_params.trait_type_constraints.map_indexed(|i, x| {
110 if i.index() < target_params.trait_type_constraints.len() {
111 x.substitute_explicits(&shape_contents)
112 } else {
113 x
114 }
115 });
116 shape_params.regions_outlive = shape_params
117 .regions_outlive
118 .into_iter()
119 .enumerate()
120 .map(|(i, x)| {
121 if i < target_params.regions_outlive.len() {
122 x.substitute_explicits(&shape_contents)
123 } else {
124 x
125 }
126 })
127 .collect();
128 shape_params.types_outlive = shape_params
129 .types_outlive
130 .into_iter()
131 .enumerate()
132 .map(|(i, x)| {
133 if i < target_params.types_outlive.len() {
134 x.substitute_explicits(&shape_contents)
135 } else {
136 x
137 }
138 })
139 .collect();
140 shape_params
141 };
142
143 shape_contents.trait_refs = shape_params.identity_args().trait_refs;
146 shape_contents
147 .trait_refs
148 .truncate(target_params.trait_clauses.len());
149
150 let shape_args = builder.extracted;
151 let shape = Binder::new(BinderKind::Other, shape_params, shape_contents);
152 (shape, shape_args)
153 }
154
155 fn replace_with_fresh_var<Id, Param, Arg>(
157 &mut self,
158 val: &mut Arg,
159 mk_param: impl FnOnce(Id) -> Param,
160 mk_value: impl FnOnce(DeBruijnVar<Id>) -> Arg,
161 ) where
162 Id: Idx + Display,
163 Arg: TyVisitable + Clone,
164 GenericParams: HasIdxVecOf<Id, Output = Param>,
165 GenericArgs: HasIdxVecOf<Id, Output = Arg>,
166 {
167 let Some(shifted_val) = val.clone().move_from_under_binders(self.binder_depth) else {
168 return;
170 };
171 self.extracted.get_idx_vec_mut().push(shifted_val);
173 let id = self.params.get_idx_vec_mut().push_with(mk_param);
175 *val = mk_value(DeBruijnVar::bound(self.binder_depth, id));
176 }
177}
178
179impl<'pm, 'ctx> VisitorWithBinderDepth for MutabilityShapeBuilder<'pm, 'ctx> {
180 fn binder_depth_mut(&mut self) -> &mut DeBruijnId {
181 &mut self.binder_depth
182 }
183}
184
185impl<'pm, 'ctx> VisitAstMut for MutabilityShapeBuilder<'pm, 'ctx> {
186 fn visit<T: AstVisitable>(&mut self, x: &mut T) -> ControlFlow<Self::Break> {
187 VisitWithBinderDepth::new(self).visit(x)
188 }
189
190 fn enter_ty(&mut self, ty: &mut Ty) {
191 if !self.pm.is_infected(ty) {
192 self.replace_with_fresh_var(
193 ty,
194 |id| TypeParam::new(id, format!("T{id}"), Variance::Unknown),
195 |v| v.into(),
196 );
197 }
198 }
199 fn exit_ty_kind(&mut self, kind: &mut TyKind) {
200 if let TyKind::Adt(TypeDeclRef {
201 id: TypeId::Adt(id),
202 generics,
203 }) = kind
204 {
205 let Some(target_params) = self.pm.generic_params.get(&(*id).into()) else {
210 return;
211 };
212 let Some(shifted_generics) =
213 generics.clone().move_from_under_binders(self.binder_depth)
214 else {
215 return;
217 };
218
219 let num_clauses_before_merge = self.params.trait_clauses.len();
221 self.params.merge_predicates_from(
222 target_params
223 .clone()
224 .substitute_explicits(&shifted_generics),
225 );
226
227 self.extracted
229 .trait_refs
230 .extend(shifted_generics.trait_refs);
231
232 for (target_clause_id, tref) in generics.trait_refs.iter_mut_enumerated() {
234 let clause_id = target_clause_id + num_clauses_before_merge;
235 *tref =
236 self.params.trait_clauses[clause_id].identity_tref_at_depth(self.binder_depth);
237 }
238 }
239 }
240 fn enter_region(&mut self, r: &mut Region) {
241 self.replace_with_fresh_var(
242 r,
243 |id| RegionParam::new(id, None, Variance::Unknown),
244 |v| v.into(),
245 );
246 }
247 fn visit_trait_ref(&mut self, _tref: &mut TraitRef) -> ControlFlow<Self::Break> {
254 ControlFlow::Continue(())
257 }
258
259 fn visit_constant_expr(
260 &mut self,
261 _: &mut ConstantExpr,
262 ) -> ::std::ops::ControlFlow<Self::Break> {
263 ControlFlow::Continue(())
264 }
265}
266
267#[derive(Visitor)]
268struct PartialMonomorphizer<'a> {
269 ctx: &'a mut TransformCtx,
270 span: Span,
272 specialize_adts: bool,
274 infected_types: HashSet<TypeDeclId>,
276 generic_params: HashMap<ItemId, GenericParams>,
281 partial_mono_shapes: SeqHashMap<(ItemId, MutabilityShape), ItemId>,
285 reverse_shape_map: HashMap<ItemId, (ItemId, MutabilityShape)>,
287 to_process: VecDeque<ItemId>,
289}
290
291impl<'a> PartialMonomorphizer<'a> {
292 pub fn new(ctx: &'a mut TransformCtx, specialize_adts: bool) -> Self {
293 let infected_types: HashSet<_> = ctx
296 .translated
297 .type_decls
298 .iter()
299 .filter(|tdecl| {
300 tdecl
301 .generics
302 .regions
303 .iter()
304 .any(|r| r.mutability.is_mutable())
305 })
306 .map(|tdecl| tdecl.def_id)
307 .collect();
308
309 let generic_params: HashMap<ItemId, GenericParams> = ctx
311 .translated
312 .all_items()
313 .map(|item| (item.id(), item.generic_params().clone()))
314 .collect();
315
316 let to_process = ctx.translated.all_ids().collect();
318 PartialMonomorphizer {
319 ctx,
320 span: Span::dummy(),
321 specialize_adts,
322 infected_types,
323 generic_params,
324 to_process,
325 partial_mono_shapes: SeqHashMap::default(),
326 reverse_shape_map: Default::default(),
327 }
328 }
329
330 fn is_infected(&self, ty: &Ty) -> bool {
333 match ty.kind() {
334 TyKind::Ref(_, _, RefKind::Mut) => true,
335 TyKind::Ref(_, ty, _)
336 | TyKind::RawPtr(ty, _)
337 | TyKind::Array(ty, _)
338 | TyKind::Pattern(ty, _)
339 | TyKind::Slice(ty) => self.is_infected(ty),
340 TyKind::Adt(tref) => match tref.id {
341 TypeId::Adt(id) => {
342 let ty_infected = self.infected_types.contains(&id);
343 let args_infected = if self.specialize_adts {
344 false
349 } else {
350 tref.generics.types.iter().any(|ty| self.is_infected(ty))
351 };
352 ty_infected || args_infected
353 }
354 TypeId::Tuple | TypeId::Builtin(_) => {
355 tref.generics.types.iter().any(|ty| self.is_infected(ty))
358 }
359 },
360 TyKind::FnDef(..) | TyKind::FnPtr(..) => false,
364 TyKind::DynTrait(_) => {
365 register_error!(
366 self.ctx,
367 self.span,
368 "`dyn Trait` is unsupported with `--monomorphize-mut`"
369 );
370 false
371 }
372 TyKind::TypeVar(..)
373 | TyKind::Literal(..)
374 | TyKind::Never
375 | TyKind::TraitType(..)
376 | TyKind::PtrMetadata(..)
377 | TyKind::Error(_) => false,
378 }
379 }
380
381 fn process_generics(&mut self, id: ItemId, generics: &GenericArgs) -> Option<DeclRef<ItemId>> {
385 if !generics.types.iter().any(|ty| self.is_infected(ty)) {
386 return None;
387 }
388
389 let mut new_generics;
392 let (id, generics) = if let Some(&(base_id, ref shape)) = self.reverse_shape_map.get(&id) {
393 new_generics = shape.clone().apply(generics);
394 let _ = self.visit(&mut new_generics); (base_id, &new_generics)
396 } else {
397 (id, generics)
398 };
399
400 let item_params = self.generic_params.get(&id)?;
402 let (shape, shape_args) =
403 MutabilityShapeBuilder::compute_shape(self, item_params, generics);
404
405 let new_params = shape.params.clone();
407 let key: (ItemId, MutabilityShape) = (id, shape);
408 let new_id = *self
409 .partial_mono_shapes
410 .entry(key.clone())
411 .or_insert_with(|| {
412 let new_id = match id {
413 ItemId::Type(_) => {
414 let new_id = self.ctx.translated.type_decls.reserve_slot();
415 self.infected_types.insert(new_id);
416 new_id.into()
417 }
418 ItemId::Fun(_) => self.ctx.translated.fun_decls.reserve_slot().into(),
419 ItemId::Global(_) => self.ctx.translated.global_decls.reserve_slot().into(),
420 ItemId::TraitDecl(_) => self.ctx.translated.trait_decls.reserve_slot().into(),
421 ItemId::TraitImpl(_) => self.ctx.translated.trait_impls.reserve_slot().into(),
422 };
423 self.generic_params.insert(new_id, new_params);
424 self.reverse_shape_map.insert(new_id, key);
425 self.to_process.push_back(new_id);
426 new_id
427 });
428
429 let fmt_ctx = self.ctx.into_fmt();
430 trace!(
431 "processing {}{}\n output: {}{}",
432 id.with_ctx(&fmt_ctx),
433 generics.with_ctx(&fmt_ctx),
434 new_id.with_ctx(&fmt_ctx),
435 shape_args.with_ctx(&fmt_ctx),
436 );
437 Some(DeclRef {
438 id: new_id,
439 generics: Box::new(shape_args),
440 trait_ref: None,
441 })
442 }
443
444 pub fn process_item(&mut self, item: &mut ItemRefMut<'_>) {
448 let _ = item.drive_mut(self);
449 }
450
451 pub fn create_pending_instantiation(&mut self, new_id: ItemId) -> ItemByVal {
456 let (orig_id, shape) = &self.reverse_shape_map[&new_id];
457 let mut decl = self
458 .ctx
459 .translated
460 .get_item(*orig_id)
461 .unwrap()
462 .to_owned()
463 .substitute_with_self(&shape.skip_binder, &TraitRefKind::SelfId);
464
465 let mut decl_mut = decl.as_mut();
466 decl_mut.set_id(new_id);
467 *decl_mut.generic_params() = shape.params.clone();
468
469 let name_ref = &mut decl_mut.item_meta().name;
470 *name_ref = mem::take::<crate::ast::Name>(name_ref).instantiate(shape.clone());
471 self.ctx
472 .translated
473 .item_names
474 .insert(new_id, decl.as_ref().item_meta().name.clone());
475 if let (ItemId::TraitDecl(orig_trait_id), ItemId::TraitDecl(new_trait_id)) =
476 (*orig_id, new_id)
477 {
478 let names = self.ctx.translated.assoc_item_names[orig_trait_id].clone();
479 self.ctx
480 .translated
481 .assoc_item_names
482 .insert(new_trait_id, names);
483 }
484
485 decl
486 }
487}
488
489impl VisitorWithSpan for PartialMonomorphizer<'_> {
490 fn current_span(&mut self) -> &mut Span {
491 &mut self.span
492 }
493}
494impl VisitAstMut for PartialMonomorphizer<'_> {
495 fn visit<T: AstVisitable>(&mut self, x: &mut T) -> ControlFlow<Self::Break> {
496 VisitWithSpan::new(self).visit(x)
498 }
499
500 fn exit_type_decl_ref(&mut self, x: &mut TypeDeclRef) {
501 if self.specialize_adts
502 && let TypeId::Adt(id) = x.id
503 && let Some(new_decl_ref) = self.process_generics(id.into(), &x.generics)
504 {
505 *x = new_decl_ref.try_into().unwrap()
506 }
507 }
508 fn exit_fn_ptr(&mut self, x: &mut FnPtr) {
509 if let FnPtrKind::Fun(FunId::Regular(id)) = *x.kind
512 && let Some(new_decl_ref) = self.process_generics(id.into(), &x.generics)
513 {
514 *x = new_decl_ref.try_into().unwrap()
515 }
516 }
517 fn exit_fun_decl_ref(&mut self, x: &mut FunDeclRef) {
518 if let Some(new_decl_ref) = self.process_generics(x.id.into(), &x.generics) {
519 *x = new_decl_ref.try_into().unwrap()
520 }
521 }
522 fn exit_global_decl_ref(&mut self, x: &mut GlobalDeclRef) {
523 if let Some(new_decl_ref) = self.process_generics(x.id.into(), &x.generics) {
524 *x = new_decl_ref.try_into().unwrap()
525 }
526 }
527 fn exit_trait_decl_ref(&mut self, x: &mut TraitDeclRef) {
528 if let Some(new_decl_ref) = self.process_generics(x.id.into(), &x.generics) {
529 *x = new_decl_ref.try_into().unwrap()
530 }
531 }
532 fn exit_trait_impl_ref(&mut self, x: &mut TraitImplRef) {
533 if let Some(new_decl_ref) = self.process_generics(x.id.into(), &x.generics) {
534 *x = new_decl_ref.try_into().unwrap()
535 }
536 }
537}
538
539pub struct Transform;
540impl TransformPass for Transform {
541 fn transform_ctx(&self, ctx: &mut TransformCtx) {
542 let Some(include_types) = ctx.options.monomorphize_mut else {
543 return;
544 };
545 let mut visitor =
547 PartialMonomorphizer::new(ctx, matches!(include_types, MonomorphizeMut::All));
548 while let Some(id) = visitor.to_process.pop_front() {
549 let mut decl = if visitor.reverse_shape_map.contains_key(&id) {
552 visitor.create_pending_instantiation(id)
554 } else {
555 match visitor.ctx.translated.remove_item_temporarily(id) {
558 Some(decl) => decl,
559 None => continue,
560 }
561 };
562 visitor.process_item(&mut decl.as_mut());
565 visitor.ctx.translated.put_item_back(id, decl);
567 }
568 }
569}