charon_lib/transform/
ops_to_function_calls.rs

1//! Desugar some unary/binary operations and the array repeats to function calls.
2//! For instance, we desugar ArrayToSlice from an unop to a function call.
3//! This allows a more uniform treatment later on.
4//! TODO: actually transform all the unops and binops to function calls?
5use crate::llbc_ast::*;
6use crate::transform::TransformCtx;
7
8use super::ctx::LlbcPass;
9
10fn transform_st(s: &mut Statement) {
11    match &s.content {
12        // Transform the ArrayToSlice unop
13        RawStatement::Assign(p, Rvalue::UnaryOp(UnOp::ArrayToSlice(ref_kind, ty, cg), op)) => {
14            // We could avoid the clone operations below if we take the content of
15            // the statement. In practice, this shouldn't have much impact.
16            let id = match ref_kind {
17                RefKind::Mut => BuiltinFunId::ArrayToSliceMut,
18                RefKind::Shared => BuiltinFunId::ArrayToSliceShared,
19            };
20            let func = FunIdOrTraitMethodRef::mk_builtin(id);
21            let generics = GenericArgs::new(
22                vec![Region::Erased].into(),
23                vec![ty.clone()].into(),
24                vec![cg.clone()].into(),
25                vec![].into(),
26                GenericsSource::Builtin,
27            );
28            let func = FnOperand::Regular(FnPtr {
29                func: Box::new(func),
30                generics: Box::new(generics),
31            });
32            s.content = RawStatement::Call(Call {
33                func,
34                args: vec![op.clone()],
35                dest: p.clone(),
36            });
37        }
38        // Transform the array aggregates to function calls
39        RawStatement::Assign(p, Rvalue::Repeat(op, ty, cg)) => {
40            // We could avoid the clone operations below if we take the content of
41            // the statement. In practice, this shouldn't have much impact.
42            let id = BuiltinFunId::ArrayRepeat;
43            let func = FunIdOrTraitMethodRef::mk_builtin(id);
44            let generics = GenericArgs::new(
45                vec![Region::Erased].into(),
46                vec![ty.clone()].into(),
47                vec![cg.clone()].into(),
48                vec![].into(),
49                GenericsSource::Builtin,
50            );
51            let func = FnOperand::Regular(FnPtr {
52                func: Box::new(func),
53                generics: Box::new(generics),
54            });
55            s.content = RawStatement::Call(Call {
56                func,
57                args: vec![op.clone()],
58                dest: p.clone(),
59            });
60        }
61        // Transform the raw pointer aggregate to a function call
62        RawStatement::Assign(p, Rvalue::Aggregate(AggregateKind::RawPtr(ty, is_mut), ops)) => {
63            let id = BuiltinFunId::PtrFromParts(is_mut.clone());
64            let func = FunIdOrTraitMethodRef::mk_builtin(id);
65            let generics = GenericArgs::new(
66                vec![Region::Erased].into(),
67                vec![ty.clone()].into(),
68                vec![].into(),
69                vec![].into(),
70                GenericsSource::Builtin,
71            );
72
73            let func = FnOperand::Regular(FnPtr {
74                func: Box::new(func),
75                generics: Box::new(generics),
76            });
77            s.content = RawStatement::Call(Call {
78                func,
79                args: ops.clone(),
80                dest: p.clone(),
81            });
82        }
83        _ => {}
84    }
85}
86
87pub struct Transform;
88impl LlbcPass for Transform {
89    fn transform_body(&self, ctx: &mut TransformCtx, b: &mut ExprBody) {
90        if ctx.options.no_ops_to_function_calls {
91            return;
92        }
93        b.body.visit_statements(&mut transform_st);
94    }
95}