patch 9.0.1559: function argument types not always checked
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)
diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim
index ffb8de4..ecdbd5e 100644
--- a/src/testdir/test_vim9_func.vim
+++ b/src/testdir/test_vim9_func.vim
Binary files differ
diff --git a/src/userfunc.c b/src/userfunc.c
index e63caf9..6f0d59d 100644
--- a/src/userfunc.c
+++ b/src/userfunc.c
@@ -3596,6 +3596,34 @@
}
/*
+ * 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
*
* Return FAIL when the function can't be called, OK otherwise.
@@ -3691,15 +3719,10 @@
}
}
- 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 @@
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 @@
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 689b1a2..47079f5 100644
--- a/src/version.c
+++ b/src/version.c
@@ -696,6 +696,8 @@
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1559,
+/**/
1558,
/**/
1557,
diff --git a/src/vim9type.c b/src/vim9type.c
index 95252db..0dd74ee 100644
--- a/src/vim9type.c
+++ b/src/vim9type.c
@@ -970,7 +970,10 @@
}
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;