Skip to content

Commit

Permalink
patch 9.0.1119: type of arguments not checked when calling a partial
Browse files Browse the repository at this point in the history
Problem:    Type of arguments not checked when calling a partial.
Solution:   Give an error for a wrong argument type. (closes #11753)
  • Loading branch information
brammool committed Dec 31, 2022
1 parent dbe6ef1 commit 0d89d8a
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 20 deletions.
26 changes: 26 additions & 0 deletions src/testdir/test_vim9_func.vim
Expand Up @@ -4277,6 +4277,32 @@ func Test_lambda_allocation_failure()
bw!
endfunc

def Test_lambda_argument_type_check()
var lines =<< trim END
vim9script

def Scan(ll: list<any>): func(func(any))
return (Emit: func(any)) => {
for e in ll
Emit(e)
endfor
}
enddef

def Sum(Cont: func(func(any))): any
var sum = 0.0
Cont((v: float) => { # <== NOTE: the lambda expects a float
sum += v
})
return sum
enddef

const ml = [3.0, 2, 7]
echo Scan(ml)->Sum()
END
v9.CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected float but got number')
enddef

def Test_multiple_funcref()
# This was using a NULL pointer
var lines =<< trim END
Expand Down
2 changes: 2 additions & 0 deletions src/version.c
Expand Up @@ -695,6 +695,8 @@ static char *(features[]) =

static int included_patches[] =
{ /* Add new patch number below this line */
/**/
1119,
/**/
1118,
/**/
Expand Down
61 changes: 41 additions & 20 deletions src/vim9execute.c
Expand Up @@ -376,6 +376,41 @@ get_pt_outer(partial_T *pt)
return &ptref->pt_outer;
}

/*
* Check "argcount" arguments on the stack against what "ufunc" expects.
* "off" is the offset of arguments on the stack.
* Return OK or FAIL.
*/
static int
check_ufunc_arg_types(ufunc_T *ufunc, int argcount, int off, ectx_T *ectx)
{
if (ufunc->uf_arg_types != NULL || ufunc->uf_va_type != NULL)
{
typval_T *argv = STACK_TV_BOT(0) - argcount - off;

// The function can change at runtime, check that the argument
// types are correct.
for (int i = 0; i < argcount; ++i)
{
type_T *type = NULL;

// assume a v:none argument, using the default value, is always OK
if (argv[i].v_type == VAR_SPECIAL
&& argv[i].vval.v_number == VVAL_NONE)
continue;

if (i < ufunc->uf_args.ga_len && ufunc->uf_arg_types != NULL)
type = ufunc->uf_arg_types[i];
else if (ufunc->uf_va_type != NULL)
type = ufunc->uf_va_type->tt_member;
if (type != NULL && check_typval_arg_type(type,
&argv[i], NULL, i + 1) == FAIL)
return FAIL;
}
}
return OK;
}

/*
* Call compiled function "cdf_idx" from compiled code.
* This adds a stack frame and sets the instruction pointer to the start of the
Expand Down Expand Up @@ -498,6 +533,10 @@ call_dfunc(
return FAIL;
}

// Check the argument types.
if (check_ufunc_arg_types(ufunc, argcount, vararg_count, ectx) == FAIL)
return FAIL;

// Reserve space for:
// - missing arguments
// - stack frame
Expand Down Expand Up @@ -1345,26 +1384,8 @@ call_by_name(

if (ufunc != NULL)
{
if (ufunc->uf_arg_types != NULL || ufunc->uf_va_type != NULL)
{
int i;
typval_T *argv = STACK_TV_BOT(0) - argcount;

// The function can change at runtime, check that the argument
// types are correct.
for (i = 0; i < argcount; ++i)
{
type_T *type = NULL;

if (i < ufunc->uf_args.ga_len && ufunc->uf_arg_types != NULL)
type = ufunc->uf_arg_types[i];
else if (ufunc->uf_va_type != NULL)
type = ufunc->uf_va_type->tt_member;
if (type != NULL && check_typval_arg_type(type,
&argv[i], NULL, i + 1) == FAIL)
return FAIL;
}
}
if (check_ufunc_arg_types(ufunc, argcount, 0, ectx) == FAIL)
return FAIL;

return call_ufunc(ufunc, NULL, argcount, ectx, iptr, selfdict);
}
Expand Down

0 comments on commit 0d89d8a

Please sign in to comment.