To: vim_dev@googlegroups.com Subject: Patch 8.2.1931 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.1931 Problem: Vim9: arguments of extend() not checked at compile time. Solution: Add argument type checking for extend(). Files: src/evalfunc.c, src/testdir/test_vim9_builtin.vim *** ../vim-8.2.1930/src/evalfunc.c 2020-10-22 12:31:45.841100292 +0200 --- src/evalfunc.c 2020-10-31 19:18:16.478754547 +0100 *************** *** 276,281 **** --- 276,284 ---- // E.g. if "arg_idx" is 1, then (type - 1) is the first argument type. typedef int (*argcheck_T)(type_T *, argcontext_T *); + /* + * Check "type" is a float or a number. + */ static int arg_float_or_nr(type_T *type, argcontext_T *context) { *************** *** 286,297 **** --- 289,315 ---- return FAIL; } + /* + * Check "type" is a number. + */ static int arg_number(type_T *type, argcontext_T *context) { return check_type(&t_number, type, TRUE, context->arg_idx + 1); } + /* + * Check "type" is a string. + */ + static int + arg_string(type_T *type, argcontext_T *context) + { + return check_type(&t_string, type, TRUE, context->arg_idx + 1); + } + + /* + * Check "type" is a list or a blob. + */ static int arg_list_or_blob(type_T *type, argcontext_T *context) { *************** *** 303,309 **** } /* ! * 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 --- 321,352 ---- } /* ! * Check "type" is a list or a dict. ! */ ! static int ! arg_list_or_dict(type_T *type, argcontext_T *context) ! { ! if (type->tt_type == VAR_ANY ! || type->tt_type == VAR_LIST || type->tt_type == VAR_DICT) ! return OK; ! arg_type_mismatch(&t_list_any, type, context->arg_idx + 1); ! return FAIL; ! } ! ! /* ! * Check "type" is the same type as the previous argument ! * Must not be used for the first argcheck_T entry. ! */ ! static int ! arg_same_as_prev(type_T *type, argcontext_T *context) ! { ! type_T *prev_type = context->arg_types[context->arg_idx - 1]; ! ! return check_type(prev_type, type, TRUE, context->arg_idx + 1); ! } ! ! /* ! * Check "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 *************** *** 324,332 **** --- 367,393 ---- } /* + * Check "type" which is the third argument of extend(). + */ + static int + arg_extend3(type_T *type, argcontext_T *context) + { + type_T *first_type = context->arg_types[context->arg_idx - 2]; + + if (first_type->tt_type == VAR_LIST) + return arg_number(type, context); + if (first_type->tt_type == VAR_DICT) + return arg_string(type, context); + return OK; + } + + + /* * Lists of functions that check the argument types of a builtin function. */ argcheck_T arg1_float_or_nr[] = {arg_float_or_nr}; + argcheck_T arg2_listblob_item[] = {arg_list_or_blob, arg_item_of_prev}; + argcheck_T arg23_extend[] = {arg_list_or_dict, arg_same_as_prev, arg_extend3}; argcheck_T arg3_insert[] = {arg_list_or_blob, arg_item_of_prev, arg_number}; /* *************** *** 567,573 **** ret_any, FLOAT_FUNC(f_abs)}, {"acos", 1, 1, FEARG_1, NULL, ret_float, FLOAT_FUNC(f_acos)}, ! {"add", 2, 2, FEARG_1, NULL, ret_first_arg, f_add}, {"and", 2, 2, FEARG_1, NULL, ret_number, f_and}, --- 628,634 ---- ret_any, FLOAT_FUNC(f_abs)}, {"acos", 1, 1, FEARG_1, NULL, ret_float, FLOAT_FUNC(f_acos)}, ! {"add", 2, 2, FEARG_1, NULL /* arg2_listblob_item */, ret_first_arg, f_add}, {"and", 2, 2, FEARG_1, NULL, ret_number, f_and}, *************** *** 793,799 **** ret_any, f_expand}, {"expandcmd", 1, 1, FEARG_1, NULL, ret_string, f_expandcmd}, ! {"extend", 2, 3, FEARG_1, NULL, ret_first_arg, f_extend}, {"feedkeys", 1, 2, FEARG_1, NULL, ret_void, f_feedkeys}, --- 854,860 ---- ret_any, f_expand}, {"expandcmd", 1, 1, FEARG_1, NULL, ret_string, f_expandcmd}, ! {"extend", 2, 3, FEARG_1, arg23_extend, ret_first_arg, f_extend}, {"feedkeys", 1, 2, FEARG_1, NULL, ret_void, f_feedkeys}, *** ../vim-8.2.1930/src/testdir/test_vim9_builtin.vim 2020-10-22 18:23:34.429289412 +0200 --- src/testdir/test_vim9_builtin.vim 2020-10-31 19:29:19.728469511 +0100 *************** *** 191,196 **** --- 191,214 ---- close enddef + def Test_extend_arg_types() + assert_equal([1, 2, 3], extend([1, 2], [3])) + assert_equal([3, 1, 2], extend([1, 2], [3], 0)) + assert_equal([1, 3, 2], extend([1, 2], [3], 1)) + + assert_equal(#{a: 1, b: 2, c: 3}, extend(#{a: 1, b: 2}, #{c: 3})) + assert_equal(#{a: 1, b: 4}, extend(#{a: 1, b: 2}, #{b: 4})) + assert_equal(#{a: 1, b: 2}, extend(#{a: 1, b: 2}, #{b: 4}, 'keep')) + + CheckDefFailure(['extend([1, 2], 3)'], 'E1013: Argument 2: type mismatch, expected list but got number') + CheckDefFailure(['extend([1, 2], ["x"])'], 'E1013: Argument 2: type mismatch, expected list but got list') + CheckDefFailure(['extend([1, 2], [3], "x")'], 'E1013: Argument 3: type mismatch, expected number but got string') + + CheckDefFailure(['extend(#{a: 1}, 42)'], 'E1013: Argument 2: type mismatch, expected dict but got number') + CheckDefFailure(['extend(#{a: 1}, #{b: "x"})'], 'E1013: Argument 2: type mismatch, expected dict but got dict') + CheckDefFailure(['extend(#{a: 1}, #{b: 2}, 1)'], 'E1013: Argument 3: type mismatch, expected string but got number') + enddef + def Test_extend_return_type() var l = extend([1, 2], [3]) var res = 0 *** ../vim-8.2.1930/src/version.c 2020-10-31 16:33:42.847372387 +0100 --- src/version.c 2020-10-31 17:22:20.908239569 +0100 *************** *** 752,753 **** --- 752,755 ---- { /* Add new patch number below this line */ + /**/ + 1931, /**/ -- You're as much use as a condom machine at the Vatican. -- Rimmer to Holly in Red Dwarf 'Queeg' /// 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 ///