To: vim_dev@googlegroups.com Subject: Patch 8.2.1879 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.1879 Problem: Vim9: argument types of insert() not checked when compiling. Solution: Add argument type checks for insert(). Files: src/evalfunc.c, src/proto/evalfunc.pro, src/vim9compile.c, src/testdir/test_vim9_builtin.vim *** ../vim-8.2.1878/src/evalfunc.c 2020-10-21 14:49:05.033959899 +0200 --- src/evalfunc.c 2020-10-21 16:34:45.971094405 +0200 *************** *** 266,273 **** // Context passed to an arg_ function. typedef struct { ! int arg_count; // actual argument count ! 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 --- 266,274 ---- // Context passed to an arg_ function. typedef struct { ! 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,293 **** static int arg_float_or_nr(type_T *type, argcontext_T *context) { ! if (type->tt_type == VAR_FLOAT || type->tt_type == VAR_NUMBER) return OK; arg_type_mismatch(&t_number, type, context->arg_idx + 1); return FAIL; } /* * Lists of functions that check the argument types of a builtin function. */ argcheck_T arg1_float_or_nr[] = {arg_float_or_nr}; /* * Functions that return the return type of a builtin function. --- 279,333 ---- static int arg_float_or_nr(type_T *type, argcontext_T *context) { ! 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,942 **** ret_number, f_inputsave}, {"inputsecret", 1, 2, FEARG_1, NULL, ret_string, f_inputsecret}, ! {"insert", 2, 3, FEARG_1, NULL, ret_first_arg, f_insert}, {"interrupt", 0, 0, 0, NULL, ret_void, f_interrupt}, --- 976,982 ---- ret_number, f_inputsave}, {"inputsecret", 1, 2, FEARG_1, NULL, ret_string, f_inputsecret}, ! {"insert", 2, 3, FEARG_1, arg3_insert, ret_first_arg, f_insert}, {"interrupt", 0, 0, 0, NULL, ret_void, f_interrupt}, *************** *** 1763,1769 **** * 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) { argcheck_T *argchecks = global_functions[idx].f_argcheck; int i; --- 1803,1809 ---- * 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) { argcheck_T *argchecks = global_functions[idx].f_argcheck; int i; *************** *** 1773,1783 **** argcontext_T context; context.arg_count = argcount; for (i = 0; i < argcount; ++i) if (argchecks[i] != NULL) { context.arg_idx = i; ! if (argchecks[i](types + i, &context) == FAIL) return FAIL; } } --- 1813,1824 ---- 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) return FAIL; } } *** ../vim-8.2.1878/src/proto/evalfunc.pro 2020-10-21 14:24:51.178015688 +0200 --- src/proto/evalfunc.pro 2020-10-21 16:35:42.202937833 +0200 *************** *** 4,10 **** 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); 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); --- 4,10 ---- 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); 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); *** ../vim-8.2.1878/src/vim9compile.c 2020-10-21 14:24:51.178015688 +0200 --- src/vim9compile.c 2020-10-21 16:35:22.594992488 +0200 *************** *** 1478,1484 **** // 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) return FAIL; if ((isn = generate_instr(cctx, ISN_BCALL)) == NULL) --- 1478,1484 ---- // 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) return FAIL; if ((isn = generate_instr(cctx, ISN_BCALL)) == NULL) *** ../vim-8.2.1878/src/testdir/test_vim9_builtin.vim 2020-10-21 14:24:51.178015688 +0200 --- src/testdir/test_vim9_builtin.vim 2020-10-21 16:39:40.290269550 +0200 *************** *** 318,330 **** index(['a', 'b', 'a', 'B'], 'b', 2, true)->assert_equal(3) enddef ! def Test_insert_return_type() var l = insert([2, 1], 3) var res = 0 for n in l res += n endfor res->assert_equal(6) enddef def Test_keys_return_type() --- 318,337 ---- index(['a', 'b', 'a', 'B'], 'b', 2, true)->assert_equal(3) enddef ! 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() *** ../vim-8.2.1878/src/version.c 2020-10-21 16:10:16.382485983 +0200 --- src/version.c 2020-10-21 16:25:06.216657068 +0200 *************** *** 752,753 **** --- 752,755 ---- { /* Add new patch number below this line */ + /**/ + 1879, /**/ -- hundred-and-one symptoms of being an internet addict: 95. Only communication in your household is through email. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///