diff options
author | Bram Moolenaar <Bram@vim.org> | 2022-12-31 14:01:24 +0000 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2022-12-31 14:01:24 +0000 |
commit | 0d89d8ae89c861572496c5ae9683d986b28c957b (patch) | |
tree | d32b5f124481c5ef169eeb5256d6c403f5ba9f3e /src | |
parent | dbe6ef1036fd50fc837b76d4e1d862a9bbbcf09b (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)
Diffstat (limited to 'src')
-rw-r--r-- | src/testdir/test_vim9_func.vim | 26 | ||||
-rw-r--r-- | src/version.c | 2 | ||||
-rw-r--r-- | src/vim9execute.c | 61 |
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); } |