charon_lib/transform/simplify_output/
remove_unused_self_clause.rs1use derive_generic_visitor::*;
5use std::collections::HashSet;
6
7use crate::ast::*;
8
9use crate::transform::{TransformCtx, ctx::TransformPass};
10
11struct FoundClause;
12
13struct UsesClauseVisitor(TraitClauseId);
14impl Visitor for UsesClauseVisitor {
15 type Break = FoundClause;
16}
17
18impl VisitAst for UsesClauseVisitor {
20 fn visit_trait_clause_id(&mut self, x: &TraitClauseId) -> ControlFlow<Self::Break> {
21 if *x == self.0 {
22 Break(FoundClause)
23 } else {
24 Continue(())
25 }
26 }
27 fn visit_trait_param(&mut self, _: &TraitParam) -> ControlFlow<Self::Break> {
28 Continue(())
31 }
32 fn visit_fun_decl(&mut self, x: &FunDecl) -> ControlFlow<Self::Break> {
33 if !x.body.has_contents() {
34 return Break(FoundClause);
37 }
38 self.visit_inner(x)
39 }
40}
41
42#[derive(Visitor)]
43struct RemoveSelfVisitor<'a> {
44 remove_in: &'a HashSet<ItemId>,
45}
46
47impl RemoveSelfVisitor<'_> {
48 fn process_item(&self, id: impl Into<ItemId>, args: &mut GenericArgs) {
49 if self.remove_in.contains(&id.into()) {
50 args.trait_refs
51 .remove_and_shift_ids(TraitClauseId::from_raw(0));
52 }
53 }
54}
55impl VisitAstMut for RemoveSelfVisitor<'_> {
56 fn enter_type_decl_ref(&mut self, x: &mut TypeDeclRef) {
57 match x.id {
58 TypeId::Adt(id) => self.process_item(id, &mut x.generics),
59 TypeId::Tuple => {}
60 TypeId::Builtin(_) => {}
61 }
62 }
63 fn enter_fun_decl_ref(&mut self, x: &mut FunDeclRef) {
64 self.process_item(x.id, &mut x.generics);
65 }
66 fn enter_fn_ptr(&mut self, x: &mut FnPtr) {
67 match x.kind.as_ref() {
68 FnPtrKind::Fun(FunId::Regular(id)) => self.process_item(*id, &mut x.generics),
69 FnPtrKind::Fun(FunId::Builtin(_)) => {}
70 FnPtrKind::Trait(..) => {}
71 }
72 }
73 fn enter_global_decl_ref(&mut self, x: &mut GlobalDeclRef) {
74 self.process_item(x.id, &mut x.generics);
75 }
76 fn enter_trait_impl_ref(&mut self, x: &mut TraitImplRef) {
77 self.process_item(x.id, &mut x.generics);
78 }
79}
80
81pub struct Transform;
82impl TransformPass for Transform {
83 fn transform_ctx(&self, ctx: &mut TransformCtx) {
84 if !ctx.options.remove_unused_self_clauses {
85 return;
86 }
87 let self_clause_id = TraitClauseId::from_raw(0);
88 let mut doesnt_use_self: HashSet<ItemId> = Default::default();
89
90 for tdecl in &ctx.translated.trait_decls {
93 let methods = tdecl
94 .methods()
95 .filter_map(|m| m.skip_binder.default.as_ref())
96 .map(|fn_ref| fn_ref.id);
97 let consts = tdecl
99 .consts
100 .iter()
101 .filter_map(|cst| cst.default.as_ref())
102 .filter_map(|gref| ctx.translated.global_decls.get(gref.id))
103 .filter_map(|gdecl| gdecl.init_fun_id());
104 let funs = methods
105 .chain(consts)
106 .filter_map(|id: FunDeclId| ctx.translated.fun_decls.get(id));
107 for fun in funs {
108 match fun.drive(&mut UsesClauseVisitor(self_clause_id)) {
109 Continue(()) => {
110 doesnt_use_self.insert(fun.def_id.into());
111 if let Some(gid) = fun.is_global_initializer {
112 doesnt_use_self.insert(gid.into());
113 }
114 }
115 Break(FoundClause) => {}
116 }
117 }
118 }
119
120 RemoveSelfVisitor {
126 remove_in: &doesnt_use_self,
127 }
128 .visit_by_val_infallible(&mut ctx.translated);
129
130 for &id in &doesnt_use_self {
132 let Some(mut item) = ctx.translated.get_item_mut(id) else {
133 continue;
134 };
135 item.generic_params()
136 .trait_clauses
137 .remove_and_shift_ids(self_clause_id);
138 item.dyn_visit_mut(|clause_id: &mut TraitClauseId| {
139 *clause_id = TraitClauseId::from_usize(clause_id.index() - 1);
140 });
141 }
142 }
143}