charon_lib/transform/simplify_output/
duplicate_defaulted_methods.rs1use crate::ast::*;
3use crate::options::TranslateOptions;
4use crate::transform::{TransformCtx, ctx::TransformPass};
5
6pub struct Transform;
7
8impl Transform {
9 fn prepare_defaulted_method_duplicate(
10 ctx: &TransformCtx,
11 trait_impl: &TraitImpl,
12 method_id: TraitMethodId,
13 method: &Binder<FunDeclRef>,
14 ) -> Option<(FunDecl, Binder<GenericArgs>)> {
15 let original_method_id = method.skip_binder.id;
16 let original_method = ctx.translated.fun_decls.get(original_method_id)?;
17 let ItemSource::TraitDecl { item_id, .. } = &original_method.src else {
18 return None;
19 };
20 let item_id = *item_id;
21 let original_method = original_method.clone();
22 let method_name = ctx
23 .translated
24 .assoc_item_name(trait_impl.impl_trait.id, method_id);
25 let mut name = ctx.translated.item_name(trait_impl.def_id).clone();
26 name.name.push(PathElem::Ident(
27 method_name.to_string(),
28 Disambiguator::ZERO,
29 ));
30
31 let subst: Binder<FunDeclRef> = Binder {
34 params: trait_impl.generics.clone(),
35 skip_binder: method.clone(),
36 kind: BinderKind::Other,
37 }
38 .flatten();
39 let mut fun_decl = original_method.substitute_params(subst.map(|x| *x.generics));
40
41 let ItemSource::TraitDecl { trait_ref, .. } = fun_decl.src else {
42 unreachable!()
43 };
44 fun_decl.def_id = FunDeclId::MAX; fun_decl.item_meta = ItemMeta {
46 name,
47 opacity: trait_impl.item_meta.opacity,
48 is_local: trait_impl.item_meta.is_local,
49 span: trait_impl.item_meta.span,
50 source_text: fun_decl.item_meta.source_text,
51 attr_info: fun_decl.item_meta.attr_info,
52 lang_item: fun_decl.item_meta.lang_item,
53 };
54 fun_decl.src = ItemSource::TraitImpl {
55 impl_ref: TraitImplRef {
56 id: trait_impl.def_id,
57 generics: Box::new(trait_impl.generics.identity_args()),
58 },
59 trait_ref,
60 item_id,
61 reuses_default: true,
62 };
63 if !trait_impl.item_meta.opacity.is_transparent() {
64 fun_decl.body = Body::Opaque;
65 }
66
67 let generics = trait_impl
68 .generics
69 .identity_args_at_depth(DeBruijnId::one())
70 .concat(&method.params.identity_args_at_depth(DeBruijnId::zero()));
71 let generics = method.map_ref(|_| generics);
72
73 Some((fun_decl, generics))
74 }
75}
76
77impl TransformPass for Transform {
78 fn should_run(&self, options: &TranslateOptions) -> bool {
79 options.duplicate_defaulted_methods
80 }
81
82 fn transform_ctx(&self, ctx: &mut TransformCtx) {
83 let duplicated_methods: IndexMap<
84 TraitImplId,
85 Vec<(TraitMethodId, FunDecl, Binder<GenericArgs>)>,
86 > = ctx.translated.trait_impls.map_ref(|trait_impl| {
87 trait_impl
88 .methods
89 .iter_indexed()
90 .filter_map(|(method_id, method)| {
91 let (fun_decl, generics) = Transform::prepare_defaulted_method_duplicate(
92 ctx, trait_impl, method_id, method,
93 )?;
94 Some((method_id, fun_decl, generics))
95 })
96 .collect()
97 });
98
99 let mut methods_to_insert: Vec<(TraitMethodId, Binder<FunDeclRef>)> = Vec::new();
100 for (trait_impl_id, duplicates) in duplicated_methods.into_iter_indexed() {
101 if duplicates.is_empty() {
102 continue;
103 }
104 for (method_id, mut fun_decl, generics) in duplicates {
105 let new_id = ctx.translated.fun_decls.reserve_slot();
106 fun_decl.def_id = new_id;
107 ctx.translated
109 .set_new_item_slot(ItemId::Fun(new_id), ItemByVal::Fun(fun_decl));
110
111 let method = generics.map(|generics| FunDeclRef {
112 id: new_id,
113 generics: Box::new(generics),
114 });
115 methods_to_insert.push((method_id, method));
116 }
117 let Some(trait_impl) = ctx.translated.trait_impls.get_mut(trait_impl_id) else {
118 continue;
119 };
120 for (method_id, method) in methods_to_insert.drain(..) {
121 trait_impl.methods.insert(method_id, method);
122 }
123 }
124 }
125}