/// Resolve a function call with named arguments
Resolve a function call with named arguments
Resolve a function call with named arguments
fn function_call_with_named_args(
    loc: &pt::Loc,
    id: &pt::Identifier,
    args: &[pt::NamedArgument],
    file_no: usize,
    function_nos: Vec<usize>,
    virtual_call: bool,
    contract_no: Option<usize>,
    ns: &mut Namespace,
    symtable: &Symtable,
    diagnostics: &mut Vec<Diagnostic>,
) -> Result<Expression, ()> {
    let mut arguments = HashMap::new();
    for arg in args {
        if arguments.contains_key(&arg.name.name) {
            diagnostics.push(Diagnostic::error(
                arg.name.loc,
                format!("duplicate argument with name ‘{}’", arg.name.name),
            ));
            return Err(());
        }
        arguments.insert(&arg.name.name, &arg.expr);
    }
    // Try to resolve as a function call
    let mut name_matches = 0;
    let mut errors = Vec::new();
    // Try to resolve as a function call
    for function_no in function_nos {
        let func = &ns.functions[function_no];
        if func.name != id.name || func.ty != pt::FunctionTy::Function {
            continue;
        }
        name_matches += 1;
        let params_len = func.params.len();
        if params_len != args.len() {
            errors.push(Diagnostic::error(
                *loc,
                format!(
                    "function expects {} arguments, {} provided",
                    params_len,
                    args.len()
                ),
            ));
            continue;
        }
        let mut matches = true;
        let mut cast_args = Vec::new();
        // check if arguments can be implicitly casted
        for i in 0..params_len {
            let param = &ns.functions[function_no].params[i];
            let arg = match arguments.get(&param.name) {
                Some(a) => a,
                None => {
                    matches = false;
                    diagnostics.push(Diagnostic::error(
                        *loc,
                        format!(
                            "missing argument ‘{}’ to function ‘{}’",
                            param.name, id.name,
                        ),
                    ));
                    break;
                }
            };
            let ty = param.ty.clone();
            let arg = match expression(
                arg,
                file_no,
                contract_no,
                ns,
                symtable,
                false,
                &mut errors,
                Some(&ty),
            ) {
                Ok(e) => e,
                Err(()) => {
                    matches = false;
                    continue;
                }
            };
            match cast(&arg.loc(), arg, &ty, true, ns, &mut errors) {
                Ok(expr) => cast_args.push(expr),
                Err(_) => {
                    matches = false;
                    continue;
                }
            }
        }
        if !matches {
            continue;
        }
        let func = &ns.functions[function_no];
        if func.contract_no != contract_no && func.is_private() {
            errors.push(Diagnostic::error_with_note(
                *loc,
                "cannot call private function".to_string(),
                func.loc,
                format!("declaration of function ‘{}’", func.name),
            ));
            continue;
        }
        let returns = function_returns(func);
        let ty = function_type(func, false);
        return Ok(Expression::InternalFunctionCall {
            loc: *loc,
            returns,
            function: Box::new(Expression::InternalFunction {
                loc: *loc,
                ty,
                function_no,
                signature: if virtual_call && (func.is_virtual || func.is_override.is_some()) {
                    Some(func.signature.clone())
                } else {
                    None
                },
            }),
            args: cast_args,
        });
    }
    match name_matches {
        0 => {
            diagnostics.push(Diagnostic::error(
                id.loc,
                format!("unknown function or type ‘{}’", id.name),
            ));
        }
        1 => diagnostics.extend(errors),
        _ => {
            diagnostics.push(Diagnostic::error(
                *loc,
                "cannot find overloaded function which matches signature".to_string(),
            ));
        }
    }
    Err(())
}
fn function_call_with_named_args ( loc : & pt :: Loc , id : & pt :: Identifier , args : & [ pt :: NamedArgument ] , file_no : usize , function_nos : Vec < usize > , virtual_call : bool , contract_no : Option < usize > , ns : & mut Namespace , symtable : & Symtable , diagnostics : & mut Vec < Diagnostic > , ) -> Result < Expression , ( ) > { let mut arguments = HashMap :: new ( ) ; for arg in args { if arguments . contains_key ( & arg . name . name ) { diagnostics . push ( Diagnostic :: error ( arg . name . loc , format ! ( " r nam .nam ), ) ) ; return Err ( ( ) ) ; } arguments . insert ( & arg . name . name , & arg . expr ) ; } // Try to resolve as a function call let mut name_matches = 0 ; let mut errors = Vec :: new ( ) ; // Try to resolve as a function call for function_no in function_nos { let func = & ns . functions [ function_no ] ; if func . name != id . name || func . ty != pt :: FunctionTy :: Function { continue ; } name_matches += 1 ; let params_len = func . params . len ( ) ; if params_len != args . len ( ) { errors . push ( Diagnostic :: error ( * loc , format ! ( " " params_len args len ( ) ) , ) ) ; continue ; } let mut matches = true ; let mut cast_args = Vec :: new ( ) ; // check if arguments can be implicitly casted for i in 0 .. params_len { let param = & ns . functions [ function_no ] . params [ i ] ; let arg = match arguments . get ( & param . name ) { Some ( a ) => a , None => { matches = false ; diagnostics . push ( Diagnostic :: error ( * loc , format ! ( " param name id name ) , ) ) ; break ; } } ; let ty = param . ty . clone ( ) ; let arg = match expression ( arg , file_no , contract_no , ns , symtable , false , & mut errors , Some ( & ty ) , ) { Ok ( e ) => e , Err ( ( ) ) => { matches = false ; continue ; } } ; match cast ( & arg . loc ( ) , arg , & ty , true , ns , & mut errors ) { Ok ( expr ) => cast_args . push ( expr ) , Err ( _ ) => { matches = false ; continue ; } } } if ! matches { continue ; } let func = & ns . functions [ function_no ] ; if func . contract_no != contract_no && func . is_private ( ) { errors . push ( Diagnostic :: error_with_note ( * loc , " " . to_string ( ) , func . loc , format ! ( " u .nam ), ) ) ; continue ; } let returns = function_returns ( func ) ; let ty = function_type ( func , false ) ; return Ok ( Expression :: InternalFunctionCall { loc : * loc , returns , function : Box :: new ( Expression :: InternalFunction { loc : * loc , ty , function_no , signature : if virtual_call && ( func . is_virtual || func . is_override . is_some ( ) ) { Some ( func . signature . clone ( ) ) } else { None } , } ) , args : cast_args , } ) ; } match name_matches { 0 => { diagnostics . push ( Diagnostic :: error ( id . loc , format ! ( " d am ), ) ) ; } 1 => diagnostics . extend ( errors ) , _ => { diagnostics . push ( Diagnostic :: error ( * loc , " " . to_string ( ) , ) ) ; } } Err ( ( ) ) }
Resolve a function call with named arguments
Resolve a function call with named arguments
loc
&pt::Loc
id
&pt::Identifier
args
&[pt::NamedArgument]
file_no
usize
function_nos
Vec<usize>
virtual_call
bool
contract_no
Option<usize>
ns
&mut Namespace
symtable
&Symtable
diagnostics
&mut Vec<Diagnostic>