To: vim_dev@googlegroups.com Subject: Patch 9.0.0629 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 9.0.0629 Problem: Get an error for using const only when executing. Solution: Check for const at compile time for filter(), map(), remove(), reverse(), sort() and uniq(). Files: src/evalfunc.c, src/testdir/test_vim9_builtin.vim *** ../vim-9.0.0628/src/evalfunc.c 2022-09-29 19:14:37.675876694 +0100 --- src/evalfunc.c 2022-09-30 17:45:51.081009611 +0100 *************** *** 214,227 **** type_T *actual, argcontext_T *context) { - // TODO: would be useful to know if "actual" is a constant and pass it to - // need_type() to get a compile time error if possible. return need_type(actual, expected, context->arg_idx - context->arg_count, context->arg_idx + 1, context->arg_cctx, FALSE, FALSE); } /* * Give an error if "type" is a constant. */ int --- 214,241 ---- type_T *actual, argcontext_T *context) { return need_type(actual, expected, context->arg_idx - context->arg_count, context->arg_idx + 1, context->arg_cctx, FALSE, FALSE); } /* + * Call need_type() to check an argument type and that it is modifiable + */ + static int + check_arg_type_mod( + type_T *expected, + type_T *actual, + argcontext_T *context) + { + if (need_type(actual, expected, + context->arg_idx - context->arg_count, context->arg_idx + 1, + context->arg_cctx, FALSE, FALSE) == FAIL) + return FAIL; + return arg_type_modifiable(actual, context->arg_idx + 1); + } + + /* * Give an error if "type" is a constant. */ int *************** *** 280,285 **** --- 294,311 ---- } /* + * Check "type" is a list of 'any' and modifiable + */ + static int + arg_list_any_mod( + type_T *type, + type_T *decl_type UNUSED, + argcontext_T *context) + { + return check_arg_type_mod(&t_list_any, type, context); + } + + /* * Check "type" is a list of numbers. */ static int *************** *** 513,528 **** /* * Check "type" is a list of 'any' or a dict of 'any' or a blob. */ static int ! arg_list_or_dict_or_blob(type_T *type, type_T *decl_type UNUSED, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN || type->tt_type == VAR_LIST || type->tt_type == VAR_DICT || type->tt_type == VAR_BLOB) ! return OK; arg_type_mismatch(&t_list_any, type, context->arg_idx + 1); return FAIL; } --- 539,558 ---- /* * Check "type" is a list of 'any' or a dict of 'any' or a blob. + * Also check if "type" is modifiable. */ static int ! arg_list_or_dict_or_blob_mod( ! type_T *type, ! type_T *decl_type UNUSED, ! argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN || type->tt_type == VAR_LIST || type->tt_type == VAR_DICT || type->tt_type == VAR_BLOB) ! return arg_type_modifiable(type, context->arg_idx + 1); arg_type_mismatch(&t_list_any, type, context->arg_idx + 1); return FAIL; } *************** *** 545,550 **** --- 575,595 ---- } /* + * Check "type" is a list of 'any' or a dict of 'any' or a blob or a string. + * Also check the value is modifiable. + */ + static int + arg_list_or_dict_or_blob_or_string_mod( + type_T *type, + type_T *decl_type, + argcontext_T *context) + { + if (arg_list_or_dict_or_blob_or_string(type, decl_type, context) == FAIL) + return FAIL; + return arg_type_modifiable(type, context->arg_idx + 1); + } + + /* * Check second argument of map() or filter(). */ static int *************** *** 994,1000 **** static argcheck_T arg1_job[] = {arg_job}; static argcheck_T arg1_list_any[] = {arg_list_any}; static argcheck_T arg1_list_number[] = {arg_list_number}; ! static argcheck_T arg1_list_or_blob[] = {arg_list_or_blob}; static argcheck_T arg1_list_or_dict[] = {arg_list_or_dict}; static argcheck_T arg1_list_string[] = {arg_list_string}; static argcheck_T arg1_string_or_list_or_dict[] = {arg_string_or_list_or_dict}; --- 1039,1045 ---- static argcheck_T arg1_job[] = {arg_job}; static argcheck_T arg1_list_any[] = {arg_list_any}; static argcheck_T arg1_list_number[] = {arg_list_number}; ! static argcheck_T arg1_list_or_blob_mod[] = {arg_list_or_blob_mod}; static argcheck_T arg1_list_or_dict[] = {arg_list_or_dict}; static argcheck_T arg1_list_string[] = {arg_list_string}; static argcheck_T arg1_string_or_list_or_dict[] = {arg_string_or_list_or_dict}; *************** *** 1091,1105 **** static argcheck_T arg1_len[] = {arg_len1}; static argcheck_T arg3_libcall[] = {arg_string, arg_string, arg_string_or_nr}; static argcheck_T arg14_maparg[] = {arg_string, arg_string, arg_bool, arg_bool}; ! static argcheck_T arg2_filter[] = {arg_list_or_dict_or_blob_or_string, arg_filter_func}; ! static argcheck_T arg2_map[] = {arg_list_or_dict_or_blob_or_string, arg_map_func}; static argcheck_T arg2_mapnew[] = {arg_list_or_dict_or_blob_or_string, NULL}; static argcheck_T arg25_matchadd[] = {arg_string, arg_string, arg_number, arg_number, arg_dict_any}; static argcheck_T arg25_matchaddpos[] = {arg_string, arg_list_any, arg_number, arg_number, arg_dict_any}; static argcheck_T arg119_printf[] = {arg_string_or_nr, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; static argcheck_T arg23_reduce[] = {arg_string_list_or_blob, NULL, NULL}; static argcheck_T arg24_remote_expr[] = {arg_string, arg_string, arg_string, arg_number}; ! static argcheck_T arg23_remove[] = {arg_list_or_dict_or_blob, arg_remove2, arg_number}; static argcheck_T arg2_repeat[] = {arg_repeat1, arg_number}; static argcheck_T arg15_search[] = {arg_string, arg_string, arg_number, arg_number, arg_string_or_func}; static argcheck_T arg37_searchpair[] = {arg_string, arg_string, arg_string, arg_string, arg_string_or_func, arg_number, arg_number}; --- 1136,1150 ---- static argcheck_T arg1_len[] = {arg_len1}; static argcheck_T arg3_libcall[] = {arg_string, arg_string, arg_string_or_nr}; static argcheck_T arg14_maparg[] = {arg_string, arg_string, arg_bool, arg_bool}; ! static argcheck_T arg2_filter[] = {arg_list_or_dict_or_blob_or_string_mod, arg_filter_func}; ! static argcheck_T arg2_map[] = {arg_list_or_dict_or_blob_or_string_mod, arg_map_func}; static argcheck_T arg2_mapnew[] = {arg_list_or_dict_or_blob_or_string, NULL}; static argcheck_T arg25_matchadd[] = {arg_string, arg_string, arg_number, arg_number, arg_dict_any}; static argcheck_T arg25_matchaddpos[] = {arg_string, arg_list_any, arg_number, arg_number, arg_dict_any}; static argcheck_T arg119_printf[] = {arg_string_or_nr, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; static argcheck_T arg23_reduce[] = {arg_string_list_or_blob, NULL, NULL}; static argcheck_T arg24_remote_expr[] = {arg_string, arg_string, arg_string, arg_number}; ! static argcheck_T arg23_remove[] = {arg_list_or_dict_or_blob_mod, arg_remove2, arg_number}; static argcheck_T arg2_repeat[] = {arg_repeat1, arg_number}; static argcheck_T arg15_search[] = {arg_string, arg_string, arg_number, arg_number, arg_string_or_func}; static argcheck_T arg37_searchpair[] = {arg_string, arg_string, arg_string, arg_string, arg_string_or_func, arg_number, arg_number}; *************** *** 1111,1117 **** static argcheck_T arg02_sign_getplaced[] = {arg_buffer, arg_dict_any}; static argcheck_T arg45_sign_place[] = {arg_number, arg_string, arg_string, arg_buffer, arg_dict_any}; static argcheck_T arg23_slice[] = {arg_slice1, arg_number, arg_number}; ! static argcheck_T arg13_sortuniq[] = {arg_list_any, arg_sort_how, arg_dict_any}; static argcheck_T arg24_strpart[] = {arg_string, arg_number, arg_number, arg_bool}; static argcheck_T arg12_system[] = {arg_string, arg_str_or_nr_or_list}; static argcheck_T arg23_win_execute[] = {arg_number, arg_string_or_list_string, arg_string}; --- 1156,1162 ---- static argcheck_T arg02_sign_getplaced[] = {arg_buffer, arg_dict_any}; static argcheck_T arg45_sign_place[] = {arg_number, arg_string, arg_string, arg_buffer, arg_dict_any}; static argcheck_T arg23_slice[] = {arg_slice1, arg_number, arg_number}; ! static argcheck_T arg13_sortuniq[] = {arg_list_any_mod, arg_sort_how, arg_dict_any}; static argcheck_T arg24_strpart[] = {arg_string, arg_number, arg_number, arg_bool}; static argcheck_T arg12_system[] = {arg_string, arg_str_or_nr_or_list}; static argcheck_T arg23_win_execute[] = {arg_number, arg_string_or_list_string, arg_string}; *************** *** 2362,2368 **** ret_repeat, f_repeat}, {"resolve", 1, 1, FEARG_1, arg1_string, ret_string, f_resolve}, ! {"reverse", 1, 1, FEARG_1, arg1_list_or_blob, ret_first_arg, f_reverse}, {"round", 1, 1, FEARG_1, arg1_float_or_nr, ret_float, f_round}, --- 2407,2413 ---- ret_repeat, f_repeat}, {"resolve", 1, 1, FEARG_1, arg1_string, ret_string, f_resolve}, ! {"reverse", 1, 1, FEARG_1, arg1_list_or_blob_mod, ret_first_arg, f_reverse}, {"round", 1, 1, FEARG_1, arg1_float_or_nr, ret_float, f_round}, *** ../vim-9.0.0628/src/testdir/test_vim9_builtin.vim 2022-09-30 11:04:47.169344522 +0100 --- src/testdir/test_vim9_builtin.vim 2022-09-30 17:47:04.828826612 +0100 *************** *** 1528,1533 **** --- 1528,1547 ---- res->assert_equal({aa: [1], ac: [3]}) enddef + def Test_filter_const() + var lines =<< trim END + const l = [1, 2, 3] + filter(l, 'v:val == 2') + END + v9.CheckDefFailure(lines, 'E1307: Argument 1: Trying to modify a const list') + + lines =<< trim END + const d = {a: 1, b: 2} + filter(d, 'v:val == 2') + END + v9.CheckDefFailure(lines, 'E1307: Argument 1: Trying to modify a const dict') + enddef + def Test_foldclosed() v9.CheckDefAndScriptFailure(['foldclosed(function("min"))'], ['E1013: Argument 1: type mismatch, expected string but got func(...): unknown', 'E1220: String or Number required for argument 1']) v9.CheckDefExecAndScriptFailure(['foldclosed("")'], 'E1209: Invalid value for a line number') *************** *** 2547,2552 **** --- 2561,2580 ---- v9.CheckDefExecAndScriptFailure(lines, 'E1012: Type mismatch; expected number but got bool') enddef + def Test_map_const() + var lines =<< trim END + const l = [1, 2, 3] + map(l, 'SomeFunc') + END + v9.CheckDefFailure(lines, 'E1307: Argument 1: Trying to modify a const list') + + lines =<< trim END + const d = {a: 1, b: 2} + map(d, 'SomeFunc') + END + v9.CheckDefFailure(lines, 'E1307: Argument 1: Trying to modify a const dict') + enddef + def Test_map_function_arg() var lines =<< trim END def MapOne(i: number, v: string): string *************** *** 3334,3345 **** v9.CheckDefAndScriptFailure(['remote_startserver({})'], ['E1013: Argument 1: type mismatch, expected string but got dict', 'E1174: String required for argument 1']) enddef ! def Test_remove_const_list() var l: list = [1, 2, 3, 4] assert_equal([1, 2], remove(l, 0, 1)) assert_equal([3, 4], l) enddef def Test_remove() v9.CheckDefAndScriptFailure(['remove("a", 1)'], ['E1013: Argument 1: type mismatch, expected list but got string', 'E1228: List, Dictionary or Blob required for argument 1']) v9.CheckDefAndScriptFailure(['remove([], "b")'], ['E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2']) --- 3362,3393 ---- v9.CheckDefAndScriptFailure(['remote_startserver({})'], ['E1013: Argument 1: type mismatch, expected string but got dict', 'E1174: String required for argument 1']) enddef ! def Test_remove_literal_list() var l: list = [1, 2, 3, 4] assert_equal([1, 2], remove(l, 0, 1)) assert_equal([3, 4], l) enddef + def Test_remove_const() + var lines =<< trim END + const l = [1, 2, 3, 4] + remove(l, 1) + END + v9.CheckDefFailure(lines, 'E1307: Argument 1: Trying to modify a const list') + + lines =<< trim END + const d = {a: 1, b: 2} + remove(d, 'a') + END + v9.CheckDefFailure(lines, 'E1307: Argument 1: Trying to modify a const dict') + + lines =<< trim END + const b = 0z010203 + remove(b, 1) + END + v9.CheckDefFailure(lines, 'E1307: Argument 1: Trying to modify a const blob') + enddef + def Test_remove() v9.CheckDefAndScriptFailure(['remove("a", 1)'], ['E1013: Argument 1: type mismatch, expected list but got string', 'E1228: List, Dictionary or Blob required for argument 1']) v9.CheckDefAndScriptFailure(['remove([], "b")'], ['E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2']) *************** *** 3419,3424 **** --- 3467,3486 ---- res->assert_equal(6) enddef + def Test_reverse_const() + var lines =<< trim END + const l = [1, 2, 3, 4] + reverse(l) + END + v9.CheckDefFailure(lines, 'E1307: Argument 1: Trying to modify a const list') + + lines =<< trim END + const b = 0z010203 + reverse(b) + END + v9.CheckDefFailure(lines, 'E1307: Argument 1: Trying to modify a const blob') + enddef + def Test_rubyeval() if !has('ruby') CheckFeature ruby *************** *** 4053,4058 **** --- 4115,4128 ---- v9.CheckScriptSuccess(lines) enddef + def Test_sort_const() + var lines =<< trim END + const l = [1, 2, 3, 4] + sort(l) + END + v9.CheckDefFailure(lines, 'E1307: Argument 1: Trying to modify a const list') + enddef + def Test_sort_compare_func_fails() v9.CheckDefAndScriptFailure(['sort("a")'], ['E1013: Argument 1: type mismatch, expected list but got string', 'E1211: List required for argument 1']) v9.CheckDefAndScriptFailure(['sort([1], "", [1])'], ['E1013: Argument 3: type mismatch, expected dict but got list', 'E1206: Dictionary required for argument 3']) *************** *** 4654,4659 **** --- 4724,4737 ---- v9.CheckDefFailure(['var l: list = uniq(["a", "b"])'], 'E1012: Type mismatch; expected list but got list') enddef + def Test_uniq_const() + var lines =<< trim END + const l = [1, 2, 3, 4] + uniq(l) + END + v9.CheckDefFailure(lines, 'E1307: Argument 1: Trying to modify a const list') + enddef + def Test_values() v9.CheckDefAndScriptFailure(['values([])'], ['E1013: Argument 1: type mismatch, expected dict but got list', 'E1206: Dictionary required for argument 1']) assert_equal([], {}->values()) *** ../vim-9.0.0628/src/version.c 2022-09-30 12:00:02.329104816 +0100 --- src/version.c 2022-09-30 16:54:10.851168233 +0100 *************** *** 701,702 **** --- 701,704 ---- { /* Add new patch number below this line */ + /**/ + 629, /**/ -- hundred-and-one symptoms of being an internet addict: 231. You sprinkle Carpet Fresh on the rugs and put your vacuum cleaner in the front doorway permanently so it always looks like you are actually attempting to do something about that mess that has amassed since you discovered the Internet. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///