charon_lib/transform/normalize/
normalize_trait_refs.rs1use crate::{
2 ast::*,
3 ids::{IndexMap, IndexVec},
4 transform::{TransformCtx, ctx::TransformPass},
5};
6
7const MAX_NORMALIZATION_STEPS: usize = 100;
8
9#[derive(Visitor)]
10struct NormalizeTraitRefs<'a> {
11 impl_parent_refs: &'a IndexMap<TraitImplId, IndexVec<TraitClauseId, PolyTraitRef>>,
12 steps: usize,
16}
17
18impl VisitAstMut for NormalizeTraitRefs<'_> {
19 fn visit_with_cached_type_info<T: AstVisitable>(
20 &mut self,
21 value: &mut WithCachedTypeInfo<T>,
22 ) -> ControlFlow<Self::Break> {
23 if value.type_info().is_normalized() {
24 ControlFlow::Continue(())
25 } else {
26 self.visit_inner(value)
27 }
28 }
29
30 fn exit_trait_ref(&mut self, tref: &mut TraitRef) {
31 if self.steps >= MAX_NORMALIZATION_STEPS {
32 return;
33 }
34 if let TraitRefKind::ParentClause(parent, clause_id, clause_args) = &tref.kind {
35 *tref = match &parent.kind {
36 TraitRefKind::TraitImpl(impl_ref) => {
37 let Some(proof) = self.impl_parent_refs.get(impl_ref.id) else {
38 return;
39 };
40 let mut proof = ItemBinder::new(impl_ref.id, proof[*clause_id].clone())
41 .substitute(ItemBinder::new(CurrentItem, &impl_ref.generics))
42 .under_current_binder()
43 .apply(clause_args.clone());
44 if *tref == proof {
45 return;
46 }
47 self.steps += 1;
49 self.visit(&mut proof);
50 proof
51 }
52 TraitRefKind::BuiltinOrAuto {
53 parent_trait_refs, ..
54 } => {
55 let Some(proof) = parent_trait_refs.get(*clause_id) else {
56 return;
57 };
58 proof.clone().apply(clause_args.clone())
59 }
60 _ => return,
61 };
62 }
63 }
64}
65
66pub struct Transform;
67impl TransformPass for Transform {
68 fn should_run(&self, options: &crate::options::TranslateOptions) -> bool {
69 !options.no_normalize
70 }
71
72 fn transform_ctx(&self, ctx: &mut TransformCtx) {
73 let impl_parent_refs = ctx
76 .translated
77 .trait_impls
78 .map_ref(|timpl| timpl.implied_trait_refs.clone());
79 ctx.for_each_item_mut(|_, mut item| {
80 let _ = item.drive_mut(&mut NormalizeTraitRefs {
81 impl_parent_refs: &impl_parent_refs,
82 steps: 0,
83 });
84 });
85 }
86}