Skip to content

Commit

Permalink
patch 9.0.1559: function argument types not always checked
Browse files Browse the repository at this point in the history
Problem:    Function argument types not always checked and using v:none may
            cause an error.
Solution:   Check argument types once the function type is known.  Do not give
            an error for using v:none as an argument. (closes #12200)
  • Loading branch information
brammool committed May 15, 2023
1 parent a2c0028 commit 2ba5123
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 12 deletions.
32 changes: 32 additions & 0 deletions src/testdir/test_vim9_func.vim
Expand Up @@ -778,6 +778,38 @@ def Test_using_vnone_default()
END
v9.CheckScriptSuccess(lines)

lines =<< trim END
vim9script

export def Floats(x: float, y = 2.0, z = 5.0)
g:result = printf("%.2f %.2f %.2f", x, y, z)
enddef
END
writefile(lines, 'Xlib.vim', 'D')

# test using a function reference in script-local variable
lines =<< trim END
vim9script

import './Xlib.vim'
const Floatfunc = Xlib.Floats
Floatfunc(1.0, v:none, 3.0)
END
v9.CheckScriptSuccess(lines)
assert_equal('1.00 2.00 3.00', g:result)
unlet g:result

# test calling the imported function
lines =<< trim END
vim9script

import './Xlib.vim'
Xlib.Floats(1.0, v:none, 3.0)
END
v9.CheckScriptSuccess(lines)
assert_equal('1.00 2.00 3.00', g:result)
unlet g:result

# TODO: this should give an error for using a missing argument
# lines =<< trim END
# vim9script
Expand Down
62 changes: 51 additions & 11 deletions src/userfunc.c
Expand Up @@ -3595,6 +3595,34 @@ user_func_error(funcerror_T error, char_u *name, int found_var)
}
}

/*
* Check the argument types "argvars[argcount]" for "name" using the
* information in "funcexe". When "base_included" then "funcexe->fe_basetv"
* is already included in "argvars[]".
* Will do nothing if "funcexe->fe_check_type" is NULL or
* "funcexe->fe_evaluate" is FALSE;
* Returns an FCERR_ value.
*/
static funcerror_T
may_check_argument_types(
funcexe_T *funcexe,
typval_T *argvars,
int argcount,
int base_included,
char_u *name)
{
if (funcexe->fe_check_type != NULL && funcexe->fe_evaluate)
{
// Check that the argument types are OK for the types of the funcref.
if (check_argument_types(funcexe->fe_check_type,
argvars, argcount,
base_included ? NULL : funcexe->fe_basetv,
name) == FAIL)
return FCERR_OTHER;
}
return FCERR_NONE;
}

/*
* Call a function with its resolved parameters
*
Expand Down Expand Up @@ -3691,15 +3719,10 @@ call_func(
}
}

if (error == FCERR_NONE && funcexe->fe_check_type != NULL
&& funcexe->fe_evaluate)
{
// Check that the argument types are OK for the types of the funcref.
if (check_argument_types(funcexe->fe_check_type,
argvars, argcount, funcexe->fe_basetv,
(name != NULL) ? name : funcname) == FAIL)
error = FCERR_OTHER;
}
if (error == FCERR_NONE)
// check the argument types if possible
error = may_check_argument_types(funcexe, argvars, argcount, FALSE,
(name != NULL) ? name : funcname);

if (error == FCERR_NONE && funcexe->fe_evaluate)
{
Expand Down Expand Up @@ -3761,10 +3784,20 @@ call_func(
error = FCERR_DELETED;
else if (fp != NULL)
{
int need_arg_check = FALSE;
if (funcexe->fe_check_type == NULL)
{
funcexe->fe_check_type = fp->uf_func_type;
need_arg_check = TRUE;
}

if (funcexe->fe_argv_func != NULL)
{
// postponed filling in the arguments, do it now
argcount = funcexe->fe_argv_func(argcount, argvars,
argv_clear, fp);
argv_clear, fp);
need_arg_check = TRUE;
}

if (funcexe->fe_basetv != NULL)
{
Expand All @@ -3774,9 +3807,16 @@ call_func(
argcount++;
argvars = argv;
argv_base = 1;
need_arg_check = TRUE;
}

error = call_user_func_check(fp, argcount, argvars, rettv,
// Check the argument types now that the function type and all
// argument values are known, if not done above.
if (need_arg_check)
error = may_check_argument_types(funcexe, argvars, argcount,
TRUE, (name != NULL) ? name : funcname);
if (error == FCERR_NONE || error == FCERR_UNKNOWN)
error = call_user_func_check(fp, argcount, argvars, rettv,
funcexe, selfdict);
}
}
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 */
/**/
1559,
/**/
1558,
/**/
Expand Down
5 changes: 4 additions & 1 deletion src/vim9type.c
Expand Up @@ -970,7 +970,10 @@ check_argument_types(
}
else
expected = type->tt_args[i];
if (check_typval_arg_type(expected, tv, NULL, i + 1) == FAIL)

// check the type, unless the value is v:none
if ((tv->v_type != VAR_SPECIAL || tv->vval.v_number != VVAL_NONE)
&& check_typval_arg_type(expected, tv, NULL, i + 1) == FAIL)
return FAIL;
}
return OK;
Expand Down

0 comments on commit 2ba5123

Please sign in to comment.