/// Resolve a function call via function type
/// Function types do not have names so call cannot be using named parameters
Resolve a function call via function type
Function types do not have names so call cannot be using named parameters
Resolve a function call via function type Function types do not have names so call cannot be using named parameters
fn call_function_type(
    loc: &pt::Loc,
    expr: &pt::Expression,
    args: &[pt::Expression],
    call_args: &[&pt::NamedArgument],
    call_args_loc: Option<pt::Loc>,
    file_no: usize,
    contract_no: Option<usize>,
    ns: &mut Namespace,
    symtable: &Symtable,
    diagnostics: &mut Vec<Diagnostic>,
) -> Result<Expression, ()> {
    let mut function = expression(
        expr,
        file_no,
        contract_no,
        ns,
        symtable,
        false,
        diagnostics,
        None,
    )?;
    let mut ty = function.ty();
    match ty {
        Type::StorageRef(real_ty) | Type::Ref(real_ty) => {
            ty = *real_ty;
            function = cast(&expr.loc(), function, &ty, true, ns, diagnostics)?;
        }
        _ => (),
    };
    if let Type::InternalFunction {
        params, returns, ..
    } = ty
    {
        if let Some(loc) = call_args_loc {
            diagnostics.push(Diagnostic::error(
                loc,
                "call arguments not permitted for internal calls".to_string(),
            ));
        }
        if params.len() != args.len() {
            diagnostics.push(Diagnostic::error(
                *loc,
                format!(
                    "function expects {} arguments, {} provided",
                    params.len(),
                    args.len()
                ),
            ));
            return Err(());
        }
        let mut cast_args = Vec::new();
        // check if arguments can be implicitly casted
        for (i, arg) in args.iter().enumerate() {
            let arg = expression(
                arg,
                file_no,
                contract_no,
                ns,
                symtable,
                false,
                diagnostics,
                Some(&params[i]),
            )?;
            cast_args.push(cast(
                &arg.loc(),
                arg.clone(),
                &params[i],
                true,
                ns,
                diagnostics,
            )?);
        }
        Ok(Expression::InternalFunctionCall {
            loc: *loc,
            returns: if returns.is_empty() {
                vec![Type::Void]
            } else {
                returns
            },
            function: Box::new(function),
            args: cast_args,
        })
    } else if let Type::ExternalFunction {
        returns,
        params,
        mutability,
    } = ty
    {
        let call_args = parse_call_args(
            call_args,
            true,
            file_no,
            contract_no,
            ns,
            symtable,
            diagnostics,
        )?;
        let value = if let Some(value) = call_args.value {
            if !value.const_zero(contract_no, ns)
                && !matches!(mutability, Some(pt::StateMutability::Payable(_)))
            {
                diagnostics.push(Diagnostic::error(
                    *loc,
                    format!(
                        "sending value to function type ‘{}’ which is not payable",
                        function.ty().to_string(ns),
                    ),
                ));
                return Err(());
            }
            value
        } else {
            Box::new(Expression::NumberLiteral(
                pt::Loc(0, 0, 0),
                Type::Value,
                BigInt::zero(),
            ))
        };
        if params.len() != args.len() {
            diagnostics.push(Diagnostic::error(
                *loc,
                format!(
                    "function expects {} arguments, {} provided",
                    params.len(),
                    args.len()
                ),
            ));
            return Err(());
        }
        let mut cast_args = Vec::new();
        // check if arguments can be implicitly casted
        for (i, arg) in args.iter().enumerate() {
            let arg = expression(
                arg,
                file_no,
                contract_no,
                ns,
                symtable,
                false,
                diagnostics,
                Some(&params[i]),
            )?;
            cast_args.push(cast(
                &arg.loc(),
                arg.clone(),
                &params[i],
                true,
                ns,
                diagnostics,
            )?);
        }
        Ok(Expression::ExternalFunctionCall {
            loc: *loc,
            returns: if returns.is_empty() {
                vec![Type::Void]
            } else {
                returns
            },
            function: Box::new(function),
            args: cast_args,
            gas: call_args.gas,
            value,
        })
    } else {
        diagnostics.push(Diagnostic::error(
            *loc,
            "expression is not a function".to_string(),
        ));
        Err(())
    }
}
fn call_function_type ( loc : & pt :: Loc , expr : & pt :: Expression , args : & [ pt :: Expression ] , call_args : & [ & pt :: NamedArgument ] , call_args_loc : Option < pt :: Loc > , file_no : usize , contract_no : Option < usize > , ns : & mut Namespace , symtable : & Symtable , diagnostics : & mut Vec < Diagnostic > , ) -> Result < Expression , ( ) > { let mut function = expression ( expr , file_no , contract_no , ns , symtable , false , diagnostics , None , ) ? ; let mut ty = function . ty ( ) ; match ty { Type :: StorageRef ( real_ty ) | Type :: Ref ( real_ty ) => { ty = * real_ty ; function = cast ( & expr . loc ( ) , function , & ty , true , ns , diagnostics ) ? ; } _ => ( ) , } ; if let Type :: InternalFunction { params , returns , .. } = ty { if let Some ( loc ) = call_args_loc { diagnostics . push ( Diagnostic :: error ( loc , " " . to_string ( ) , ) ) ; } if params . len ( ) != args . len ( ) { diagnostics . push ( Diagnostic :: error ( * loc , format ! ( " " params len ( ) args len ( ) ) , ) ) ; return Err ( ( ) ) ; } let mut cast_args = Vec :: new ( ) ; // check if arguments can be implicitly casted for ( i , arg ) in args . iter ( ) . enumerate ( ) { let arg = expression ( arg , file_no , contract_no , ns , symtable , false , diagnostics , Some ( & params [ i ] ) , ) ? ; cast_args . push ( cast ( & arg . loc ( ) , arg . clone ( ) , & params [ i ] , true , ns , diagnostics , ) ? ) ; } Ok ( Expression :: InternalFunctionCall { loc : * loc , returns : if returns . is_empty ( ) { vec ! [ Type Void ] } else { returns } , function : Box :: new ( function ) , args : cast_args , } ) } else if let Type :: ExternalFunction { returns , params , mutability , } = ty { let call_args = parse_call_args ( call_args , true , file_no , contract_no , ns , symtable , diagnostics , ) ? ; let value = if let Some ( value ) = call_args . value { if ! value . const_zero ( contract_no , ns ) && ! matches ! ( mutability Some ( pt StateMutability Payable ( ) ) ) { diagnostics . push ( Diagnostic :: error ( * loc , format ! ( " function ty ( ) to_string ( ns ) ) , ) ) ; return Err ( ( ) ) ; } value } else { Box :: new ( Expression :: NumberLiteral ( pt :: Loc ( 0 , 0 , 0 ) , Type :: Value , BigInt :: zero ( ) , ) ) } ; if params . len ( ) != args . len ( ) { diagnostics . push ( Diagnostic :: error ( * loc , format ! ( " " params len ( ) args len ( ) ) , ) ) ; return Err ( ( ) ) ; } let mut cast_args = Vec :: new ( ) ; // check if arguments can be implicitly casted for ( i , arg ) in args . iter ( ) . enumerate ( ) { let arg = expression ( arg , file_no , contract_no , ns , symtable , false , diagnostics , Some ( & params [ i ] ) , ) ? ; cast_args . push ( cast ( & arg . loc ( ) , arg . clone ( ) , & params [ i ] , true , ns , diagnostics , ) ? ) ; } Ok ( Expression :: ExternalFunctionCall { loc : * loc , returns : if returns . is_empty ( ) { vec ! [ Type Void ] } else { returns } , function : Box :: new ( function ) , args : cast_args , gas : call_args . gas , value , } ) } else { diagnostics . push ( Diagnostic :: error ( * loc , " " . to_string ( ) , ) ) ; Err ( ( ) ) } }
Resolve a function call via function type
Function types do not have names so call cannot be using named parameters
Resolve a function call via function type Function types do not have names so call cannot be using named parameters
loc
&pt::Loc
expr
&pt::Expression
args
&[pt::Expression]
call_args
&[&pt::NamedArgument]
call_args_loc
Option<pt::Loc>
file_no
usize
contract_no
Option<usize>
ns
&mut Namespace
symtable
&Symtable
diagnostics
&mut Vec<Diagnostic>