charon_lib/transform/
duplicate_defaulted_methods.rs1use std::{collections::HashMap, mem};
3
4use crate::ast::*;
5
6use super::{ctx::TransformPass, TransformCtx};
7
8pub struct Transform;
9impl TransformPass for Transform {
10 fn transform_ctx(&self, ctx: &mut TransformCtx) {
11 for impl_id in ctx.translated.trait_impls.all_indices() {
12 let Some(timpl) = ctx.translated.trait_impls.get_mut(impl_id) else {
13 continue;
14 };
15 let Some(tdecl) = ctx.translated.trait_decls.get(timpl.impl_trait.id) else {
16 continue;
17 };
18 if tdecl.methods.len() == timpl.methods.len() {
19 continue;
20 }
21
22 let self_impl_ref = TraitImplRef {
24 id: timpl.def_id,
25 generics: Box::new(timpl.generics.identity_args()),
26 };
27 let self_predicate = TraitRef {
28 kind: TraitRefKind::TraitImpl(self_impl_ref.clone()),
29 trait_decl_ref: RegionBinder::empty(timpl.impl_trait.clone()),
30 };
31 let mut methods_map: HashMap<TraitItemName, _> =
33 mem::take(&mut timpl.methods).into_iter().collect();
34 let timpl = ctx.translated.trait_impls.get(impl_id).unwrap();
36 let mut methods = vec![];
37 for (name, decl_fn_ref) in &tdecl.methods {
38 if let Some(kv) = methods_map.remove_entry(name) {
39 methods.push(kv);
40 continue;
41 }
42 let declared_fun_id = decl_fn_ref.skip_binder.id;
43 let declared_fun_name = ctx.translated.item_name(declared_fun_id).unwrap();
44 let new_fun_name = {
45 let mut item_name = timpl.item_meta.name.clone();
46 item_name
47 .name
48 .push(declared_fun_name.name.last().unwrap().clone());
49 item_name
50 };
51 let opacity = ctx.opacity_for_name(&new_fun_name);
52 let new_fun_id = ctx.translated.fun_decls.reserve_slot();
53 ctx.translated
54 .item_names
55 .insert(new_fun_id.into(), new_fun_name.clone());
56
57 let bound_fn = decl_fn_ref
59 .clone()
60 .substitute_with_self(&timpl.impl_trait.generics, &self_predicate.kind);
61 let new_fn_ref = Binder {
65 skip_binder: FunDeclRef {
66 id: new_fun_id,
67 generics: Box::new(
68 timpl
69 .generics
70 .identity_args_at_depth(DeBruijnId::one())
71 .concat(
72 &bound_fn.params.identity_args_at_depth(DeBruijnId::zero()),
73 ),
74 ),
75 },
76 params: bound_fn.params.clone(),
77 kind: bound_fn.kind.clone(),
78 };
79 methods.push((name.clone(), new_fn_ref));
80
81 if let Some(fun_decl) = ctx.translated.fun_decls.get(declared_fun_id)
82 && !opacity.is_invisible()
83 {
84 let bound_fn = Binder {
85 params: timpl.generics.clone(),
86 skip_binder: bound_fn,
87 kind: BinderKind::Other,
88 };
89 let bound_fn = bound_fn.flatten();
93 let FunDecl {
95 def_id: _,
96 item_meta,
97 signature,
98 kind,
99 is_global_initializer,
100 body,
101 } = fun_decl.clone();
102 let span = timpl.item_meta.span;
105 let item_meta = ItemMeta {
106 name: new_fun_name,
107 is_local: timpl.item_meta.is_local,
108 opacity,
109 span,
110 ..item_meta
111 };
112 let signature = FunSig {
113 generics: bound_fn.params,
114 inputs: signature.inputs.substitute_with_self(
115 &bound_fn.skip_binder.generics,
116 &self_predicate.kind,
117 ),
118 output: signature.output.substitute_with_self(
119 &bound_fn.skip_binder.generics,
120 &self_predicate.kind,
121 ),
122 ..signature
123 };
124 let kind = if let ItemKind::TraitDecl {
125 trait_ref,
126 item_name,
127 ..
128 } = kind
129 {
130 ItemKind::TraitImpl {
131 impl_ref: self_impl_ref.clone(),
132 trait_ref: trait_ref.substitute_with_self(
133 &bound_fn.skip_binder.generics,
134 &self_predicate.kind,
135 ),
136 item_name,
137 reuses_default: true,
138 }
139 } else {
140 unreachable!()
141 };
142 let body = if opacity.is_transparent() {
143 body.substitute_with_self(
144 &bound_fn.skip_binder.generics,
145 &self_predicate.kind,
146 )
147 } else {
148 Err(Opaque)
149 };
150 ctx.translated.fun_decls.set_slot(
151 new_fun_id,
152 FunDecl {
153 def_id: new_fun_id,
154 item_meta,
155 signature,
156 kind,
157 is_global_initializer,
158 body,
159 },
160 );
161 }
162 }
163 let timpl = ctx.translated.trait_impls.get_mut(impl_id).unwrap();
164 timpl.methods = methods;
165 }
166 }
167}