diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim index ffb8de48dd0b0..ecdbd5eacaa99 100644 --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -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 diff --git a/src/userfunc.c b/src/userfunc.c index e63caf9fed3da..6f0d59dfd36fe 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -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 * @@ -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) { @@ -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) { @@ -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); } } diff --git a/src/version.c b/src/version.c index 689b1a2c75b5c..47079f5331cbb 100644 --- a/src/version.c +++ b/src/version.c @@ -695,6 +695,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1559, /**/ 1558, /**/ diff --git a/src/vim9type.c b/src/vim9type.c index 95252dbafeda3..0dd74ee184be6 100644 --- a/src/vim9type.c +++ b/src/vim9type.c @@ -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;