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