charon_lib/transform/simplify_output/
remove_adt_clauses.rs1use std::collections::HashSet;
10
11use derive_generic_visitor::*;
12
13use crate::ast::*;
14use crate::common::CycleDetector;
15use crate::ids::{IndexMap, IndexVec};
16use crate::transform::{TransformCtx, ctx::TransformPass};
17
18fn has_assoc_types(
20 translated: &TranslatedCrate,
21 cache: &mut IndexMap<TraitDeclId, CycleDetector<bool>>,
22 id: TraitDeclId,
23) -> bool {
24 if cache[id].start_processing() {
25 let result = match translated.trait_decls.get(id) {
26 Some(tdecl) => {
27 !tdecl.types.is_empty()
28 || tdecl
29 .implied_clauses
30 .iter()
31 .any(|p| has_assoc_types(translated, cache, p.trait_.skip_binder.id))
32 }
33 None => false,
34 };
35 cache[id].done_processing(result);
36 }
37 match &cache[id] {
38 CycleDetector::Processed(b) => *b,
39 CycleDetector::Cyclic | CycleDetector::Processing => false,
40 CycleDetector::Unprocessed => unreachable!(),
41 }
42}
43
44fn untouchable_adts(translated: &TranslatedCrate) -> HashSet<TypeDeclId> {
47 let mut cache: IndexMap<TraitDeclId, CycleDetector<bool>> = translated
48 .trait_decls
49 .map_ref_opt(|_| Some(CycleDetector::Unprocessed));
50 translated
51 .type_decls
52 .iter()
53 .filter(|d| {
54 d.generics
55 .trait_clauses
56 .iter()
57 .any(|c| has_assoc_types(translated, &mut cache, c.trait_.skip_binder.id))
58 })
59 .map(|d| d.def_id)
60 .collect()
61}
62
63#[derive(Visitor)]
64struct RemoveAdtClausesVisitor<'a> {
65 translated: &'a TranslatedCrate,
66 untouchable_adts: &'a HashSet<TypeDeclId>,
67 binder_stack: BindingStack<GenericParams>,
68}
69
70impl VisitorWithBinderStack for RemoveAdtClausesVisitor<'_> {
71 fn binder_stack_mut(&mut self) -> &mut BindingStack<GenericParams> {
72 &mut self.binder_stack
73 }
74}
75
76impl VisitAstMut for RemoveAdtClausesVisitor<'_> {
77 fn visit<T: AstVisitable>(&mut self, x: &mut T) -> ::std::ops::ControlFlow<Self::Break> {
78 VisitWithBinderStack::new(self).visit(x)?;
79 ::std::ops::ControlFlow::Continue(())
80 }
81
82 fn enter_type_decl(&mut self, decl: &mut TypeDecl) {
83 if self.untouchable_adts.contains(&decl.def_id) {
84 return;
85 }
86 decl.generics.trait_clauses.clear();
87 decl.generics.trait_type_constraints.clear();
88 *self.binder_stack.innermost_mut() = decl.generics.clone();
92 }
93
94 fn enter_type_decl_ref(&mut self, tref: &mut TypeDeclRef) {
95 if let TypeId::Adt(id) = tref.id
96 && !self.untouchable_adts.contains(&id)
97 {
98 tref.generics.trait_refs.clear();
99 }
100 }
101
102 fn enter_trait_ref(&mut self, tref: &mut TraitRef) {
103 let TraitRefKind::Clause(var) = &tref.kind else {
104 return;
105 };
106 if self
107 .binder_stack
108 .get_var::<_, GenericParams>(*var)
109 .is_some()
110 {
111 return;
112 }
113 let new_kind = build_removed_clause_placeholder(self.translated, &tref.trait_decl_ref);
114 tref.with_contents_mut(|contents| contents.kind = new_kind);
115 }
116}
117
118fn build_removed_clause_placeholder(
126 translated: &TranslatedCrate,
127 trait_decl_ref: &PolyTraitDeclRef,
128) -> TraitRefKind {
129 let trait_id = trait_decl_ref.skip_binder.id;
130 let stub_tref = TraitRef::new(
131 TraitRefKind::BuiltinOrAuto {
132 builtin_data: BuiltinImplData::RemovedAdtClause,
133 parent_trait_refs: Default::default(),
134 types: Default::default(),
135 },
136 trait_decl_ref.clone(),
137 );
138 let parent_trait_refs: IndexVec<TraitClauseId, TraitRef> = translated
139 .trait_decls
140 .get(trait_id)
141 .map(|tdecl| {
142 Substituted::new_for_trait_ref(&tdecl.implied_clauses, &stub_tref)
143 .iter()
144 .map(|s| {
145 let parent: TraitParam = s.substitute();
146 let kind = build_removed_clause_placeholder(translated, &parent.trait_);
147 TraitRef::new(kind, parent.trait_)
148 })
149 .collect()
150 })
151 .unwrap_or_default();
152 TraitRefKind::BuiltinOrAuto {
153 builtin_data: BuiltinImplData::RemovedAdtClause,
154 parent_trait_refs,
155 types: Default::default(),
156 }
157}
158
159pub struct Transform;
160impl TransformPass for Transform {
161 fn transform_ctx(&self, ctx: &mut TransformCtx) {
162 if !ctx.options.remove_adt_clauses {
163 return;
164 }
165 let untouchable = untouchable_adts(&ctx.translated);
166 ctx.for_each_item_mut(|ctx, mut item| {
167 let _ = item.drive_mut(&mut RemoveAdtClausesVisitor {
168 translated: &ctx.translated,
169 untouchable_adts: &untouchable,
170 binder_stack: BindingStack::empty(),
171 });
172 });
173 }
174}