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 FunSource::TraitDefault { 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 FunSource::TraitDefault { 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 started_from: false,
50 is_extern: fun_decl.item_meta.is_extern,
51 span: trait_impl.item_meta.span,
52 source_text: fun_decl.item_meta.source_text,
53 attr_info: fun_decl.item_meta.attr_info,
54 lang_item: fun_decl.item_meta.lang_item,
55 diagnostic_item: fun_decl.item_meta.diagnostic_item,
56 has_errors: fun_decl.item_meta.has_errors,
57 };
58 fun_decl.src = FunSource::TraitImpl {
59 impl_ref: TraitImplRef {
60 id: trait_impl.def_id,
61 generics: Box::new(trait_impl.generics.identity_args()),
62 },
63 trait_ref,
64 item_id,
65 reuses_default: true,
66 };
67 if !trait_impl.item_meta.opacity.is_transparent() {
68 fun_decl.body = Body::Opaque;
69 }
70
71 let generics = trait_impl
72 .generics
73 .identity_args_at_depth(DeBruijnId::one())
74 .concat(&method.params.identity_args_at_depth(DeBruijnId::zero()));
75 let generics = method.map_ref(|_| generics);
76
77 Some((fun_decl, generics))
78 }
79}
80
81impl TransformPass for Transform {
82 fn should_run(&self, options: &TranslateOptions) -> bool {
83 options.duplicate_defaulted_methods
84 }
85
86 fn transform_ctx(&self, ctx: &mut TransformCtx) {
87 let duplicated_methods: IndexMap<
88 TraitImplId,
89 Vec<(TraitMethodId, FunDecl, Binder<GenericArgs>)>,
90 > = ctx.translated.trait_impls.map_ref(|trait_impl| {
91 trait_impl
92 .methods
93 .iter_indexed()
94 .filter_map(|(method_id, method)| {
95 let (fun_decl, generics) = Transform::prepare_defaulted_method_duplicate(
96 ctx, trait_impl, method_id, method,
97 )?;
98 Some((method_id, fun_decl, generics))
99 })
100 .collect()
101 });
102
103 let mut methods_to_insert: Vec<(TraitMethodId, Binder<FunDeclRef>)> = Vec::new();
104 for (trait_impl_id, duplicates) in duplicated_methods.into_iter_indexed() {
105 if duplicates.is_empty() {
106 continue;
107 }
108 for (method_id, mut fun_decl, generics) in duplicates {
109 let new_id = ctx.translated.fun_decls.reserve_slot();
110 fun_decl.def_id = new_id;
111 ctx.translated
113 .set_new_item_slot(ItemId::Fun(new_id), ItemByVal::Fun(fun_decl));
114
115 let method = generics.map(|generics| FunDeclRef {
116 id: new_id,
117 generics: Box::new(generics),
118 });
119 methods_to_insert.push((method_id, method));
120 }
121 let Some(trait_impl) = ctx.translated.trait_impls.get_mut(trait_impl_id) else {
122 continue;
123 };
124 for (method_id, method) in methods_to_insert.drain(..) {
125 trait_impl.methods.insert(method_id, method);
126 }
127 }
128 }
129}