cairo_lang_sierra/extensions/modules/
function_call.rs

1use itertools::chain;
2
3use super::coupon::coupon_ty;
4use crate::extensions::lib_func::{
5    LibfuncSignature, OutputVarInfo, SignatureBasedConcreteLibfunc, SignatureSpecializationContext,
6    SpecializationContext,
7};
8use crate::extensions::{
9    NamedLibfunc, OutputVarReferenceInfo, SpecializationError, args_as_single_user_func,
10};
11use crate::program::{Function, FunctionSignature, GenericArg};
12
13/// Returns the [OutputVarInfo] instances for the return types of the given function signature.
14fn get_output_var_infos(
15    context: &dyn SignatureSpecializationContext,
16    signature: FunctionSignature,
17) -> Result<Vec<OutputVarInfo>, SpecializationError> {
18    let mut curr_stack_idx = 0;
19    let mut get_stack_idx = || {
20        let idx = curr_stack_idx;
21        curr_stack_idx += 1;
22        idx
23    };
24
25    signature
26        .ret_types
27        .iter()
28        .map(|ty| {
29            Ok(OutputVarInfo {
30                ty: ty.clone(),
31                ref_info: if context.get_type_info(ty.clone())?.zero_sized {
32                    OutputVarReferenceInfo::ZeroSized
33                } else {
34                    OutputVarReferenceInfo::NewTempVar { idx: get_stack_idx() }
35                },
36            })
37        })
38        .collect::<Result<Vec<_>, _>>()
39}
40
41/// Libfunc used to call user functions.
42#[derive(Default)]
43pub struct FunctionCallLibfunc {}
44impl NamedLibfunc for FunctionCallLibfunc {
45    type Concrete = SignatureAndFunctionConcreteLibfunc;
46    const STR_ID: &'static str = "function_call";
47
48    fn specialize_signature(
49        &self,
50        context: &dyn SignatureSpecializationContext,
51        args: &[GenericArg],
52    ) -> Result<LibfuncSignature, SpecializationError> {
53        let function_id = args_as_single_user_func(args)?;
54
55        let signature = context.get_function_signature(&function_id)?;
56        let ap_change = context.get_function_ap_change(&function_id)?;
57        Ok(LibfuncSignature::new_non_branch(
58            signature.param_types.clone(),
59            get_output_var_infos(context, signature)?,
60            ap_change,
61        ))
62    }
63
64    fn specialize(
65        &self,
66        context: &dyn SpecializationContext,
67        args: &[GenericArg],
68    ) -> Result<Self::Concrete, SpecializationError> {
69        let function_id = args_as_single_user_func(args)?;
70
71        Ok(Self::Concrete {
72            function: context.get_function(&function_id)?,
73            signature: self.specialize_signature(context.upcast(), args)?,
74        })
75    }
76}
77
78pub struct SignatureAndFunctionConcreteLibfunc {
79    pub function: Function,
80    pub signature: LibfuncSignature,
81}
82impl SignatureBasedConcreteLibfunc for SignatureAndFunctionConcreteLibfunc {
83    fn signature(&self) -> &LibfuncSignature {
84        &self.signature
85    }
86}
87
88/// Libfunc used to call user functions.
89#[derive(Default)]
90pub struct CouponCallLibfunc {}
91impl NamedLibfunc for CouponCallLibfunc {
92    type Concrete = SignatureAndFunctionConcreteLibfunc;
93    const STR_ID: &'static str = "coupon_call";
94
95    fn specialize_signature(
96        &self,
97        context: &dyn SignatureSpecializationContext,
98        args: &[GenericArg],
99    ) -> Result<LibfuncSignature, SpecializationError> {
100        let function_id = args_as_single_user_func(args)?;
101
102        let signature = context.get_function_signature(&function_id)?;
103        let ap_change = context.get_function_ap_change(&function_id)?;
104
105        let coupon_ty = coupon_ty(context, function_id.clone())?;
106        Ok(LibfuncSignature::new_non_branch(
107            chain!(signature.param_types.iter().cloned(), [coupon_ty]).collect(),
108            get_output_var_infos(context, signature)?,
109            ap_change,
110        ))
111    }
112
113    fn specialize(
114        &self,
115        context: &dyn SpecializationContext,
116        args: &[GenericArg],
117    ) -> Result<Self::Concrete, SpecializationError> {
118        let function_id = args_as_single_user_func(args)?;
119
120        Ok(Self::Concrete {
121            function: context.get_function(&function_id)?,
122            signature: self.specialize_signature(context.upcast(), args)?,
123        })
124    }
125}