diff options
author | Bram Moolenaar <Bram@vim.org> | 2020-10-21 16:42:22 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2020-10-21 16:42:22 +0200 |
commit | ca17453e73fe69dc25a9d703804877a60763b685 (patch) | |
tree | 224ea9cada39389b9409a9ebb97c46990ed57b00 | |
parent | 8a99e66b4f7616d9b0b9cefe742f82f9122087d5 (diff) | |
download | vim-git-ca17453e73fe69dc25a9d703804877a60763b685.tar.gz |
patch 8.2.1879: Vim9: argument types of insert() not checked when compilingv8.2.1879
Problem: Vim9: argument types of insert() not checked when compiling.
Solution: Add argument type checks for insert().
-rw-r--r-- | src/evalfunc.c | 53 | ||||
-rw-r--r-- | src/proto/evalfunc.pro | 2 | ||||
-rw-r--r-- | src/testdir/test_vim9_builtin.vim | 9 | ||||
-rw-r--r-- | src/version.c | 2 | ||||
-rw-r--r-- | src/vim9compile.c | 2 |
5 files changed, 59 insertions, 9 deletions
diff --git a/src/evalfunc.c b/src/evalfunc.c index d782d8494..41133091d 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -266,8 +266,9 @@ static void f_xor(typval_T *argvars, typval_T *rettv); // Context passed to an arg_ function. typedef struct { - int arg_count; // actual argument count - int arg_idx; // current argument index (first arg is zero) + int arg_count; // actual argument count + type_T **arg_types; // list of argument types + int arg_idx; // current argument index (first arg is zero) } argcontext_T; // A function to check one argument type. The first argument is the type to @@ -278,16 +279,55 @@ typedef int (*argcheck_T)(type_T *, argcontext_T *); static int arg_float_or_nr(type_T *type, argcontext_T *context) { - if (type->tt_type == VAR_FLOAT || type->tt_type == VAR_NUMBER) + if (type->tt_type == VAR_ANY + || type->tt_type == VAR_FLOAT || type->tt_type == VAR_NUMBER) return OK; arg_type_mismatch(&t_number, type, context->arg_idx + 1); return FAIL; } + static int +arg_number(type_T *type, argcontext_T *context) +{ + return check_type(&t_number, type, TRUE, context->arg_idx + 1); +} + + static int +arg_list_or_blob(type_T *type, argcontext_T *context) +{ + if (type->tt_type == VAR_ANY + || type->tt_type == VAR_LIST || type->tt_type == VAR_BLOB) + return OK; + arg_type_mismatch(&t_list_any, type, context->arg_idx + 1); + return FAIL; +} + +/* + * Check the type is an item of the list or blob of the previous arg. + * Must not be used for the first argcheck_T entry. + */ + static int +arg_item_of_prev(type_T *type, argcontext_T *context) +{ + type_T *prev_type = context->arg_types[context->arg_idx - 1]; + type_T *expected; + + if (prev_type->tt_type == VAR_LIST) + expected = prev_type->tt_member; + else if (prev_type->tt_type == VAR_BLOB) + expected = &t_number; + else + // probably VAR_ANY, can't check + return OK; + + return check_type(expected, type, TRUE, context->arg_idx + 1); +} + /* * Lists of functions that check the argument types of a builtin function. */ argcheck_T arg1_float_or_nr[] = {arg_float_or_nr}; +argcheck_T arg3_insert[] = {arg_list_or_blob, arg_item_of_prev, arg_number}; /* * Functions that return the return type of a builtin function. @@ -936,7 +976,7 @@ static funcentry_T global_functions[] = ret_number, f_inputsave}, {"inputsecret", 1, 2, FEARG_1, NULL, ret_string, f_inputsecret}, - {"insert", 2, 3, FEARG_1, NULL, + {"insert", 2, 3, FEARG_1, arg3_insert, ret_first_arg, f_insert}, {"interrupt", 0, 0, 0, NULL, ret_void, f_interrupt}, @@ -1763,7 +1803,7 @@ internal_func_name(int idx) * Return FAIL and gives an error message when a type is wrong. */ int -internal_func_check_arg_types(type_T *types, int idx, int argcount) +internal_func_check_arg_types(type_T **types, int idx, int argcount) { argcheck_T *argchecks = global_functions[idx].f_argcheck; int i; @@ -1773,11 +1813,12 @@ internal_func_check_arg_types(type_T *types, int idx, int argcount) argcontext_T context; context.arg_count = argcount; + context.arg_types = types; for (i = 0; i < argcount; ++i) if (argchecks[i] != NULL) { context.arg_idx = i; - if (argchecks[i](types + i, &context) == FAIL) + if (argchecks[i](types[i], &context) == FAIL) return FAIL; } } diff --git a/src/proto/evalfunc.pro b/src/proto/evalfunc.pro index 6cc81db0c..c649b861b 100644 --- a/src/proto/evalfunc.pro +++ b/src/proto/evalfunc.pro @@ -4,7 +4,7 @@ char_u *get_expr_name(expand_T *xp, int idx); int find_internal_func(char_u *name); int has_internal_func(char_u *name); char *internal_func_name(int idx); -int internal_func_check_arg_types(type_T *types, int idx, int argcount); +int internal_func_check_arg_types(type_T **types, int idx, int argcount); type_T *internal_func_ret_type(int idx, int argcount, type_T **argtypes); int check_internal_func(int idx, int argcount); int call_internal_func(char_u *name, int argcount, typval_T *argvars, typval_T *rettv); diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim index fb94746c7..e3d7bb628 100644 --- a/src/testdir/test_vim9_builtin.vim +++ b/src/testdir/test_vim9_builtin.vim @@ -318,13 +318,20 @@ def Test_index() index(['a', 'b', 'a', 'B'], 'b', 2, true)->assert_equal(3) enddef -def Test_insert_return_type() +def Test_insert() var l = insert([2, 1], 3) var res = 0 for n in l res += n endfor res->assert_equal(6) + + assert_equal([1, 2, 3], insert([2, 3], 1)) + assert_equal([1, 2, 3], insert([1, 2], 3, 2)) + assert_equal(['a', 'b', 'c'], insert(['b', 'c'], 'a')) + assert_equal(0z1234, insert(0z34, 0x12)) + CheckDefFailure(['insert([2, 3], "a")'], 'E1013: Argument 2: type mismatch, expected number but got string', 1) + CheckDefFailure(['insert([2, 3], 1, "x")'], 'E1013: Argument 3: type mismatch, expected number but got string', 1) enddef def Test_keys_return_type() diff --git a/src/version.c b/src/version.c index 78e47525a..a49bdd386 100644 --- a/src/version.c +++ b/src/version.c @@ -751,6 +751,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1879, +/**/ 1878, /**/ 1877, diff --git a/src/vim9compile.c b/src/vim9compile.c index 289b941bf..8ef1f0873 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -1478,7 +1478,7 @@ generate_BCALL(cctx_T *cctx, int func_idx, int argcount, int method_call) // Check the types of the arguments. argtypes = ((type_T **)stack->ga_data) + stack->ga_len - argcount; if (argcount > 0 && internal_func_check_arg_types( - *argtypes, func_idx, argcount) == FAIL) + argtypes, func_idx, argcount) == FAIL) return FAIL; if ((isn = generate_instr(cctx, ISN_BCALL)) == NULL) |