charon_lib/transform/
skip_trait_refs_when_known.rs

1use crate::{register_error, transform::TransformCtx, ullbc_ast::*};
2
3use super::ctx::UllbcPass;
4
5fn transform_call(ctx: &mut TransformCtx, span: Span, call: &mut Call) {
6    // We find calls to a trait method where the impl is known; otherwise we return.
7    let FnOperand::Regular(fn_ptr) = &mut call.func else {
8        return;
9    };
10    let FunIdOrTraitMethodRef::Trait(trait_ref, name, _) = &fn_ptr.func else {
11        return;
12    };
13    let TraitRefKind::TraitImpl(impl_id, impl_generics) = &trait_ref.kind else {
14        return;
15    };
16    let Some(trait_impl) = &ctx.translated.trait_impls.get(*impl_id) else {
17        return;
18    };
19    // Find the function declaration corresponding to this impl.
20    let Some((_, bound_fn)) = trait_impl.methods().find(|(n, _)| n == name) else {
21        return;
22    };
23    let method_generics = &fn_ptr.generics;
24
25    if !method_generics.matches(&bound_fn.params) {
26        register_error!(
27            ctx,
28            span,
29            "Mismatched method generics:\nparams:   {:?}\nsupplied: {:?}",
30            bound_fn.params,
31            method_generics
32        );
33    }
34
35    // Make the two levels of binding explicit: outer binder for the impl block, inner binder for
36    // the method.
37    let fn_ref: Binder<Binder<FunDeclRef>> = Binder::new(
38        BinderKind::Other,
39        trait_impl.generics.clone(),
40        bound_fn.clone(),
41    );
42    // Substitute the appropriate generics into the function call.
43    let fn_ref = fn_ref.apply(impl_generics).apply(method_generics);
44    fn_ptr.generics = fn_ref.generics;
45    fn_ptr.func = FunIdOrTraitMethodRef::Fun(FunId::Regular(fn_ref.id));
46}
47
48pub struct Transform;
49impl UllbcPass for Transform {
50    fn transform_body(&self, ctx: &mut TransformCtx, b: &mut ExprBody) {
51        for block in b.body.iter_mut() {
52            for st in block.statements.iter_mut() {
53                if let RawStatement::Call(call) = &mut st.content {
54                    transform_call(ctx, st.span, call)
55                };
56            }
57        }
58    }
59}