summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2022-12-31 14:01:24 +0000
committerBram Moolenaar <Bram@vim.org>2022-12-31 14:01:24 +0000
commit0d89d8ae89c861572496c5ae9683d986b28c957b (patch)
treed32b5f124481c5ef169eeb5256d6c403f5ba9f3e
parentdbe6ef1036fd50fc837b76d4e1d862a9bbbcf09b (diff)
patch 9.0.1119: type of arguments not checked when calling a partialv9.0.1119
Problem: Type of arguments not checked when calling a partial. Solution: Give an error for a wrong argument type. (closes #11753)
-rw-r--r--src/testdir/test_vim9_func.vim26
-rw-r--r--src/version.c2
-rw-r--r--src/vim9execute.c61
3 files changed, 69 insertions, 20 deletions
diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim
index 0edf7eab71..3840d1144f 100644
--- a/src/testdir/test_vim9_func.vim
+++ b/src/testdir/test_vim9_func.vim
@@ -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
diff --git a/src/version.c b/src/version.c
index a66b58893a..92c70ea99e 100644
--- a/src/version.c
+++ b/src/version.c
@@ -696,6 +696,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1119,
+/**/
1118,
/**/
1117,
diff --git a/src/vim9execute.c b/src/vim9execute.c
index 06229b884a..2bc81c38b1 100644
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -377,6 +377,41 @@ get_pt_outer(partial_T *pt)
}
/*
+ * 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
* called function.
@@ -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
@@ -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);
}