# HG changeset patch # User Bram Moolenaar # Date 1627155904 -7200 # Node ID 1cde96e768e48865257be8426924e35ba336df93 # Parent efef27c0f8a01cd038c17229edd41f5c1047915a patch 8.2.3215: Vim9: argument types are not checked at compile time Commit: https://github.com/vim/vim/commit/5bca906b307728fa74a112914dc55b424d512d39 Author: Yegappan Lakshmanan Date: Sat Jul 24 21:33:26 2021 +0200 patch 8.2.3215: Vim9: argument types are not checked at compile time Problem: Vim9: argument types are not checked at compile time. Solution: Add several more type checks. Sort the argument lists. (Yegappan Lakshmanan, closes #8626) diff --git a/src/change.c b/src/change.c --- a/src/change.c +++ b/src/change.c @@ -241,6 +241,9 @@ f_listener_add(typval_T *argvars, typval listener_T *lnr; buf_T *buf = curbuf; + if (in_vim9script() && check_for_opt_buffer_arg(argvars, 1) == FAIL) + return; + callback = get_callback(&argvars[0]); if (callback.cb_name == NULL) return; diff --git a/src/evalfunc.c b/src/evalfunc.c --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -644,83 +644,91 @@ arg_cursor1(type_T *type, argcontext_T * /* * Lists of functions that check the argument types of a builtin function. */ -static argcheck_T arg1_string[] = {arg_string}; -static argcheck_T arg1_number[] = {arg_number}; static argcheck_T arg1_bool[] = {arg_bool}; -static argcheck_T arg1_list_any[] = {arg_list_any}; +static argcheck_T arg1_buffer[] = {arg_buffer}; +static argcheck_T arg1_buffer_or_dict_any[] = {arg_buffer_or_dict_any}; +static argcheck_T arg1_chan_or_job[] = {arg_chan_or_job}; static argcheck_T arg1_dict_any[] = {arg_dict_any}; +static argcheck_T arg1_dict_or_string[] = {arg_dict_any_or_string}; +static argcheck_T arg1_float_or_nr[] = {arg_float_or_nr}; static argcheck_T arg1_job[] = {arg_job}; -static argcheck_T arg1_buffer[] = {arg_buffer}; -static argcheck_T arg1_lnum[] = {arg_lnum}; +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_float_or_nr[] = {arg_float_or_nr}; -static argcheck_T arg1_string_or_nr[] = {arg_string_or_nr}; +static argcheck_T arg1_lnum[] = {arg_lnum}; +static argcheck_T arg1_number[] = {arg_number}; +static argcheck_T arg1_string[] = {arg_string}; static argcheck_T arg1_string_or_list_any[] = {arg_string_or_list_any}; static argcheck_T arg1_string_or_list_string[] = {arg_string_or_list_string}; -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_chan_or_job[] = {arg_chan_or_job}; -static argcheck_T arg1_dict_or_string[] = {arg_dict_any_or_string}; -static argcheck_T arg1_buffer_or_dict_any[] = {arg_buffer_or_dict_any}; +static argcheck_T arg1_string_or_nr[] = {arg_string_or_nr}; +static argcheck_T arg2_any_buffer[] = {NULL, arg_buffer}; +static argcheck_T arg2_buffer_any[] = {arg_buffer, NULL}; +static argcheck_T arg2_buffer_bool[] = {arg_buffer, arg_bool}; +static argcheck_T arg2_buffer_list_any[] = {arg_buffer, arg_list_any}; +static argcheck_T arg2_buffer_lnum[] = {arg_buffer, arg_lnum}; +static argcheck_T arg2_buffer_number[] = {arg_buffer, arg_number}; +static argcheck_T arg2_buffer_string[] = {arg_buffer, arg_string}; +static argcheck_T arg2_chan_or_job_dict[] = {arg_chan_or_job, arg_dict_any}; +static argcheck_T arg2_chan_or_job_string[] = {arg_chan_or_job, arg_string}; +static argcheck_T arg2_dict_any_string_or_nr[] = {arg_dict_any, arg_string_or_nr}; +static argcheck_T arg2_dict_string[] = {arg_dict_any, arg_string}; static argcheck_T arg2_float_or_nr[] = {arg_float_or_nr, arg_float_or_nr}; -static argcheck_T arg2_number[] = {arg_number, arg_number}; -static argcheck_T arg2_string[] = {arg_string, arg_string}; -static argcheck_T arg2_string_number[] = {arg_string, arg_number}; -static argcheck_T arg2_string_dict[] = {arg_string, arg_dict_any}; -static argcheck_T arg2_string_list_nr[] = {arg_string, arg_list_number}; -static argcheck_T arg2_string_bool[] = {arg_string, arg_bool}; -static argcheck_T arg2_string_or_list_dict[] = {arg_string_or_list_any, arg_dict_any}; -static argcheck_T arg2_string_string_or_number[] = {arg_string, arg_string_or_nr}; -static argcheck_T arg2_string_chan_or_job[] = {arg_string, arg_chan_or_job}; +static argcheck_T arg2_job_dict[] = {arg_job, arg_dict_any}; +static argcheck_T arg2_job_string_or_number[] = {arg_job, arg_string_or_nr}; +static argcheck_T arg2_list_any_number[] = {arg_list_any, arg_number}; +static argcheck_T arg2_list_any_string[] = {arg_list_any, arg_string}; static argcheck_T arg2_list_number[] = {arg_list_number, arg_list_number}; static argcheck_T arg2_list_number_bool[] = {arg_list_number, arg_bool}; -static argcheck_T arg2_list_any_string[] = {arg_list_any, arg_string}; -static argcheck_T arg2_list_any_number[] = {arg_list_any, arg_number}; -static argcheck_T arg2_number_string[] = {arg_number, arg_string}; -static argcheck_T arg2_number_bool[] = {arg_number, arg_bool}; -static argcheck_T arg2_number_list[] = {arg_number, arg_list_any}; -static argcheck_T arg2_number_dict_any[] = {arg_number, arg_dict_any}; -static argcheck_T arg2_number_string_or_list[] = {arg_number, arg_string_or_list_any}; -static argcheck_T arg2_dict_string[] = {arg_dict_any, arg_string}; -static argcheck_T arg2_dict_any_string_or_nr[] = {arg_dict_any, arg_string_or_nr}; -static argcheck_T arg2_job_dict[] = {arg_job, arg_dict_any}; -static argcheck_T arg2_job_string_or_number[] = {arg_job, arg_string_or_nr}; static argcheck_T arg2_listblob_item[] = {arg_list_or_blob, arg_item_of_prev}; -static argcheck_T arg2_str_or_nr_or_list_dict[] = {arg_str_or_nr_or_list, arg_dict_any}; static argcheck_T arg2_lnum[] = {arg_lnum, arg_lnum}; static argcheck_T arg2_lnum_number[] = {arg_lnum, arg_number}; -static argcheck_T arg2_chan_or_job_dict[] = {arg_chan_or_job, arg_dict_any}; -static argcheck_T arg2_chan_or_job_string[] = {arg_chan_or_job, arg_string}; -static argcheck_T arg2_buffer_string[] = {arg_buffer, arg_string}; -static argcheck_T arg2_buffer_number[] = {arg_buffer, arg_number}; -static argcheck_T arg2_buffer_bool[] = {arg_buffer, arg_bool}; -static argcheck_T arg2_buffer_lnum[] = {arg_buffer, arg_lnum}; -static argcheck_T arg2_buffer_list_any[] = {arg_buffer, arg_list_any}; -static argcheck_T arg2_buffer_any[] = {arg_buffer, NULL}; -static argcheck_T arg3_string[] = {arg_string, arg_string, arg_string}; +static argcheck_T arg2_number[] = {arg_number, arg_number}; +static argcheck_T arg2_number_bool[] = {arg_number, arg_bool}; +static argcheck_T arg2_number_dict_any[] = {arg_number, arg_dict_any}; +static argcheck_T arg2_number_list[] = {arg_number, arg_list_any}; +static argcheck_T arg2_number_string[] = {arg_number, arg_string}; +static argcheck_T arg2_number_string_or_list[] = {arg_number, arg_string_or_list_any}; +static argcheck_T arg2_str_or_nr_or_list_dict[] = {arg_str_or_nr_or_list, arg_dict_any}; +static argcheck_T arg2_string[] = {arg_string, arg_string}; +static argcheck_T arg2_string_any[] = {arg_string, NULL}; +static argcheck_T arg2_string_bool[] = {arg_string, arg_bool}; +static argcheck_T arg2_string_chan_or_job[] = {arg_string, arg_chan_or_job}; +static argcheck_T arg2_string_dict[] = {arg_string, arg_dict_any}; +static argcheck_T arg2_string_list_number[] = {arg_string, arg_list_number}; +static argcheck_T arg2_string_number[] = {arg_string, arg_number}; +static argcheck_T arg2_string_or_list_dict[] = {arg_string_or_list_any, arg_dict_any}; +static argcheck_T arg2_string_string_or_number[] = {arg_string, arg_string_or_nr}; +static argcheck_T arg3_any_list_dict[] = {NULL, arg_list_any, arg_dict_any}; +static argcheck_T arg3_buffer_lnum_lnum[] = {arg_buffer, arg_lnum, arg_lnum}; +static argcheck_T arg3_buffer_number_number[] = {arg_buffer, arg_number, arg_number}; +static argcheck_T arg3_buffer_string_any[] = {arg_buffer, arg_string, NULL}; +static argcheck_T arg3_buffer_string_dict[] = {arg_buffer, arg_string, arg_dict_any}; +static argcheck_T arg3_dict_number_number[] = {arg_dict_any, arg_number, arg_number}; +static argcheck_T arg3_list_string_dict[] = {arg_list_any, arg_string, arg_dict_any}; +static argcheck_T arg3_lnum_number_bool[] = {arg_lnum, arg_number, arg_bool}; static argcheck_T arg3_number[] = {arg_number, arg_number, arg_number}; +static argcheck_T arg3_number_any_dict[] = {arg_number, NULL, arg_dict_any}; static argcheck_T arg3_number_number_dict[] = {arg_number, arg_number, arg_dict_any}; -static argcheck_T arg3_number_string_string[] = {arg_number, arg_string, arg_string}; static argcheck_T arg3_number_string_any[] = {arg_number, arg_string, NULL}; static argcheck_T arg3_number_string_buffer[] = {arg_number, arg_string, arg_buffer}; -static argcheck_T arg3_number_any_dict[] = {arg_number, NULL, arg_dict_any}; -static argcheck_T arg3_string_nr_bool[] = {arg_string, arg_number, arg_bool}; -static argcheck_T arg3_string_string_nr[] = {arg_string, arg_string, arg_number}; -static argcheck_T arg3_string_string_dict[] = {arg_string, arg_string, arg_dict_any}; -static argcheck_T arg3_string_string_bool[] = {arg_string, arg_string, arg_bool}; +static argcheck_T arg3_number_string_string[] = {arg_number, arg_string, arg_string}; +static argcheck_T arg3_string[] = {arg_string, arg_string, arg_string}; +static argcheck_T arg3_string_any_dict[] = {arg_string, NULL, arg_dict_any}; static argcheck_T arg3_string_bool_bool[] = {arg_string, arg_bool, arg_bool}; static argcheck_T arg3_string_bool_dict[] = {arg_string, arg_bool, arg_dict_any}; -static argcheck_T arg3_list_string_dict[] = {arg_list_any, arg_string, arg_dict_any}; -static argcheck_T arg3_dict_number_number[] = {arg_dict_any, arg_number, arg_number}; -static argcheck_T arg3_lnum_number_bool[] = {arg_lnum, arg_number, arg_bool}; -static argcheck_T arg3_buffer_lnum_lnum[] = {arg_buffer, arg_lnum, arg_lnum}; -static argcheck_T arg3_buffer_number_number[] = {arg_buffer, arg_number, arg_number}; -static argcheck_T arg3_buffer_string_dict[] = {arg_buffer, arg_string, arg_dict_any}; -static argcheck_T arg3_buffer_string_any[] = {arg_buffer, arg_string, NULL}; +static argcheck_T arg3_string_number_bool[] = {arg_string, arg_number, arg_bool}; +static argcheck_T arg3_string_number_number[] = {arg_string, arg_number, arg_number}; +static argcheck_T arg3_string_string_bool[] = {arg_string, arg_string, arg_bool}; +static argcheck_T arg3_string_string_dict[] = {arg_string, arg_string, arg_dict_any}; +static argcheck_T arg3_string_string_nr[] = {arg_string, arg_string, arg_number}; +static argcheck_T arg4_list_number_number_number[] = {arg_list_string, arg_number, arg_number, arg_number}; static argcheck_T arg4_number_number_string_any[] = {arg_number, arg_number, arg_string, NULL}; +static argcheck_T arg4_string_string_any_string[] = {arg_string, arg_string, NULL, arg_string}; static argcheck_T arg4_string_string_number_string[] = {arg_string, arg_string, arg_number, arg_string}; static argcheck_T arg5_number[] = {arg_number, arg_number, arg_number, arg_number, arg_number}; +/* Function specific argument types (not covered by the above) */ static argcheck_T arg4_browse[] = {arg_bool, arg_string, arg_string, arg_string}; static argcheck_T arg23_chanexpr[] = {arg_chan_or_job, NULL, arg_dict_any}; static argcheck_T arg23_chanraw[] = {arg_chan_or_job, arg_string_or_blob, arg_dict_any}; @@ -734,8 +742,9 @@ static argcheck_T arg14_glob[] = {arg_st static argcheck_T arg25_globpath[] = {arg_string, arg_string, arg_bool, arg_bool, arg_bool}; static argcheck_T arg24_index[] = {arg_list_or_blob, arg_item_of_prev, arg_number, arg_bool}; static argcheck_T arg23_insert[] = {arg_list_or_blob, arg_item_of_prev, arg_number}; +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_mapfilter[] = {arg_list_or_dict_or_blob, NULL}; -static argcheck_T arg14_maparg[] = {arg_string, arg_string, arg_bool, arg_bool}; 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 arg23_reduce[] = {arg_list_or_blob, NULL, NULL}; @@ -1138,7 +1147,7 @@ static funcentry_T global_functions[] = ret_number, f_byteidx}, {"byteidxcomp", 2, 2, FEARG_1, arg2_string_number, ret_number, f_byteidxcomp}, - {"call", 2, 3, FEARG_1, NULL, + {"call", 2, 3, FEARG_1, arg3_any_list_dict, ret_any, f_call}, {"ceil", 1, 1, FEARG_1, arg1_float_or_nr, ret_float, FLOAT_FUNC(f_ceil)}, @@ -1186,7 +1195,7 @@ static funcentry_T global_functions[] = ret_number, f_charclass}, {"charcol", 1, 1, FEARG_1, arg1_string_or_list_any, ret_number, f_charcol}, - {"charidx", 2, 3, FEARG_1, arg3_string_nr_bool, + {"charidx", 2, 3, FEARG_1, arg3_string_number_bool, ret_number, f_charidx}, {"chdir", 1, 1, FEARG_1, arg1_string, ret_string, f_chdir}, @@ -1310,9 +1319,9 @@ static funcentry_T global_functions[] = ret_void, f_foreground}, {"fullcommand", 1, 1, FEARG_1, arg1_string, ret_string, f_fullcommand}, - {"funcref", 1, 3, FEARG_1, NULL, + {"funcref", 1, 3, FEARG_1, arg3_any_list_dict, ret_func_any, f_funcref}, - {"function", 1, 3, FEARG_1, NULL, + {"function", 1, 3, FEARG_1, arg3_any_list_dict, ret_f_function, f_function}, {"garbagecollect", 0, 1, 0, arg1_bool, ret_void, f_garbagecollect}, @@ -1508,9 +1517,9 @@ static funcentry_T global_functions[] = ret_number, f_last_buffer_nr}, {"len", 1, 1, FEARG_1, NULL, ret_number, f_len}, - {"libcall", 3, 3, FEARG_3, NULL, + {"libcall", 3, 3, FEARG_3, arg3_libcall, ret_string, f_libcall}, - {"libcallnr", 3, 3, FEARG_3, NULL, + {"libcallnr", 3, 3, FEARG_3, arg3_libcall, ret_number, f_libcallnr}, {"line", 1, 2, FEARG_1, arg2_string_number, ret_number, f_line}, @@ -1520,7 +1529,7 @@ static funcentry_T global_functions[] = ret_number, f_lispindent}, {"list2str", 1, 2, FEARG_1, arg2_list_number_bool, ret_string, f_list2str}, - {"listener_add", 1, 2, FEARG_2, NULL, + {"listener_add", 1, 2, FEARG_2, arg2_any_buffer, ret_number, f_listener_add}, {"listener_flush", 0, 1, FEARG_1, arg1_buffer, ret_void, f_listener_flush}, @@ -1722,9 +1731,9 @@ static funcentry_T global_functions[] = ret_list_number, f_range}, {"readblob", 1, 1, FEARG_1, arg1_string, ret_blob, f_readblob}, - {"readdir", 1, 3, FEARG_1, NULL, + {"readdir", 1, 3, FEARG_1, arg3_string_any_dict, ret_list_string, f_readdir}, - {"readdirex", 1, 3, FEARG_1, NULL, + {"readdirex", 1, 3, FEARG_1, arg3_string_any_dict, ret_list_dict_any, f_readdirex}, {"readfile", 1, 3, FEARG_1, arg3_string_string_nr, ret_list_string, f_readfile}, @@ -1808,7 +1817,7 @@ static funcentry_T global_functions[] = ret_void, f_setbufvar}, {"setcellwidths", 1, 1, FEARG_1, arg1_list_any, ret_void, f_setcellwidths}, - {"setcharpos", 2, 2, FEARG_2, arg2_string_list_nr, + {"setcharpos", 2, 2, FEARG_2, arg2_string_list_number, ret_number_bool, f_setcharpos}, {"setcharsearch", 1, 1, FEARG_1, arg1_dict_any, ret_void, f_setcharsearch}, @@ -1830,7 +1839,7 @@ static funcentry_T global_functions[] = ret_number_bool, f_setloclist}, {"setmatches", 1, 2, FEARG_1, arg2_list_any_number, ret_number_bool, f_setmatches}, - {"setpos", 2, 2, FEARG_2, arg2_string_list_nr, + {"setpos", 2, 2, FEARG_2, arg2_string_list_number, ret_number_bool, f_setpos}, {"setqflist", 1, 3, FEARG_1, arg13_setqflist, ret_number_bool, f_setqflist}, @@ -1886,9 +1895,9 @@ static funcentry_T global_functions[] = ret_first_arg, f_sort}, {"sound_clear", 0, 0, 0, NULL, ret_void, SOUND_FUNC(f_sound_clear)}, - {"sound_playevent", 1, 2, FEARG_1, NULL, + {"sound_playevent", 1, 2, FEARG_1, arg2_string_any, ret_number, SOUND_FUNC(f_sound_playevent)}, - {"sound_playfile", 1, 2, FEARG_1, NULL, + {"sound_playfile", 1, 2, FEARG_1, arg2_string_any, ret_number, SOUND_FUNC(f_sound_playfile)}, {"sound_stop", 1, 1, FEARG_1, arg1_number, ret_void, SOUND_FUNC(f_sound_stop)}, @@ -1896,7 +1905,7 @@ static funcentry_T global_functions[] = ret_string, f_soundfold}, {"spellbadword", 0, 1, FEARG_1, arg1_string, ret_list_string, f_spellbadword}, - {"spellsuggest", 1, 3, FEARG_1, arg3_string_nr_bool, + {"spellsuggest", 1, 3, FEARG_1, arg3_string_number_bool, ret_list_string, f_spellsuggest}, {"split", 1, 3, FEARG_1, arg3_string_string_bool, ret_list_string, f_split}, @@ -1910,7 +1919,7 @@ static funcentry_T global_functions[] = ret_float, FLOAT_FUNC(f_str2float)}, {"str2list", 1, 2, FEARG_1, arg2_string_bool, ret_list_number, f_str2list}, - {"str2nr", 1, 3, FEARG_1, arg3_string_nr_bool, + {"str2nr", 1, 3, FEARG_1, arg3_string_number_bool, ret_number, f_str2nr}, {"strcharlen", 1, 1, FEARG_1, arg1_string_or_nr, ret_number, f_strcharlen}, @@ -1954,7 +1963,7 @@ static funcentry_T global_functions[] = ret_number, f_strwidth}, {"submatch", 1, 2, FEARG_1, arg2_number_bool, ret_string, f_submatch}, - {"substitute", 4, 4, FEARG_1, NULL, + {"substitute", 4, 4, FEARG_1, arg4_string_string_any_string, ret_string, f_substitute}, {"swapinfo", 1, 1, FEARG_1, arg1_string, ret_dict_any, f_swapinfo}, @@ -2064,7 +2073,7 @@ static funcentry_T global_functions[] = ret_void, f_test_garbagecollect_soon}, {"test_getvalue", 1, 1, FEARG_1, arg1_string, ret_number, f_test_getvalue}, - {"test_gui_drop_files", 4, 4, 0, NULL, + {"test_gui_drop_files", 4, 4, 0, arg4_list_number_number_number, ret_void, f_test_gui_drop_files}, {"test_gui_mouse_event", 5, 5, 0, arg5_number, ret_void, f_test_gui_mouse_event}, @@ -2092,7 +2101,7 @@ static funcentry_T global_functions[] = ret_void, f_test_override}, {"test_refcount", 1, 1, FEARG_1, NULL, ret_number, f_test_refcount}, - {"test_scrollbar", 3, 3, FEARG_2, NULL, + {"test_scrollbar", 3, 3, FEARG_2, arg3_string_number_number, ret_void, #ifdef FEAT_GUI f_test_scrollbar @@ -2682,6 +2691,11 @@ f_call(typval_T *argvars, typval_T *rett partial_T *partial = NULL; dict_T *selfdict = NULL; + if (in_vim9script() + && (check_for_list_arg(argvars, 1) == FAIL + || check_for_opt_dict_arg(argvars, 2) == FAIL)) + return; + if (argvars[1].v_type != VAR_LIST) { emsg(_(e_listreq)); @@ -3734,6 +3748,12 @@ common_function(typval_T *argvars, typva char_u *trans_name = NULL; int is_global = FALSE; + if (in_vim9script() + && (check_for_opt_list_arg(argvars, 1) == FAIL + || (argvars[1].v_type != VAR_UNKNOWN + && check_for_opt_dict_arg(argvars, 2) == FAIL))) + return; + if (argvars[0].v_type == VAR_FUNC) { // function(MyFunc, [arg], dict) @@ -6417,6 +6437,12 @@ libcall_common(typval_T *argvars UNUSED, if (check_restricted() || check_secure()) return; + if (in_vim9script() + && (check_for_string_arg(argvars, 0) == FAIL + || check_for_string_arg(argvars, 1) == FAIL + || check_for_string_or_number_arg(argvars, 2) == FAIL)) + return; + #ifdef FEAT_LIBCALL // The first two args must be strings, otherwise it's meaningless if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING) @@ -9177,12 +9203,21 @@ f_substitute(typval_T *argvars, typval_T char_u patbuf[NUMBUFLEN]; char_u subbuf[NUMBUFLEN]; char_u flagsbuf[NUMBUFLEN]; - - char_u *str = tv_get_string_chk(&argvars[0]); - char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf); + char_u *str; + char_u *pat; char_u *sub = NULL; typval_T *expr = NULL; - char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf); + char_u *flg; + + if (in_vim9script() + && (check_for_string_arg(argvars, 0) == FAIL + || check_for_string_arg(argvars, 1) == FAIL + || check_for_string_arg(argvars, 3) == FAIL)) + return; + + str = tv_get_string_chk(&argvars[0]); + pat = tv_get_string_buf_chk(&argvars[1], patbuf); + flg = tv_get_string_buf_chk(&argvars[3], flagsbuf); if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL) expr = &argvars[2]; diff --git a/src/filepath.c b/src/filepath.c --- a/src/filepath.c +++ b/src/filepath.c @@ -1602,6 +1602,13 @@ f_readdir(typval_T *argvars, typval_T *r if (rettv_list_alloc(rettv) == FAIL) return; + + if (in_vim9script() + && (check_for_string_arg(argvars, 0) == FAIL + || (argvars[1].v_type != VAR_UNKNOWN + && check_for_opt_dict_arg(argvars, 2) == FAIL))) + return; + path = tv_get_string(&argvars[0]); expr = &argvars[1]; @@ -1648,6 +1655,13 @@ f_readdirex(typval_T *argvars, typval_T if (rettv_list_alloc(rettv) == FAIL) return; + + if (in_vim9script() + && (check_for_string_arg(argvars, 0) == FAIL + || (argvars[1].v_type != VAR_UNKNOWN + && check_for_opt_dict_arg(argvars, 2) == FAIL))) + return; + path = tv_get_string(&argvars[0]); expr = &argvars[1]; diff --git a/src/sound.c b/src/sound.c --- a/src/sound.c +++ b/src/sound.c @@ -179,6 +179,9 @@ invoke_sound_callback(void) static void sound_play_common(typval_T *argvars, typval_T *rettv, int playfile) { + if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL) + return; + if (context == NULL) ca_context_create(&context); if (context != NULL) @@ -351,6 +354,9 @@ f_sound_playevent(typval_T *argvars, typ { WCHAR *wp; + if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL) + return; + wp = enc_to_utf16(tv_get_string(&argvars[0]), NULL); if (wp == NULL) return; @@ -371,6 +377,9 @@ f_sound_playfile(typval_T *argvars, typv char buf[32]; MCIERROR err; + if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL) + return; + esc = vim_strsave_shellescape(tv_get_string(&argvars[0]), FALSE, FALSE); len = STRLEN(esc) + 5 + 18 + 1; diff --git a/src/testdir/test_gui.vim b/src/testdir/test_gui.vim --- a/src/testdir/test_gui.vim +++ b/src/testdir/test_gui.vim @@ -1172,10 +1172,10 @@ endfunc func Test_gui_drop_files() CheckFeature drop_file - call assert_fails('call test_gui_drop_files(1, 1, 1, 0)', 'E474:') - call assert_fails('call test_gui_drop_files(["x"], "", 1, 0)', 'E474:') - call assert_fails('call test_gui_drop_files(["x"], 1, "", 0)', 'E474:') - call assert_fails('call test_gui_drop_files(["x"], 1, 1, "")', 'E474:') + call assert_fails('call test_gui_drop_files(1, 1, 1, 0)', 'E1211:') + call assert_fails('call test_gui_drop_files(["x"], "", 1, 0)', 'E1210:') + call assert_fails('call test_gui_drop_files(["x"], 1, "", 0)', 'E1210:') + call assert_fails('call test_gui_drop_files(["x"], 1, 1, "")', 'E1210:') %bw! %argdelete diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim --- a/src/testdir/test_vim9_builtin.vim +++ b/src/testdir/test_vim9_builtin.vim @@ -373,6 +373,8 @@ def Test_call_call() var l = [3, 2, 1] call('reverse', [l]) l->assert_equal([1, 2, 3]) + CheckDefAndScriptFailure2(['call("reverse", 2)'], 'E1013: Argument 2: type mismatch, expected list but got number', 'E1211: List required for argument 2') + CheckDefAndScriptFailure2(['call("reverse", [2], [1])'], 'E1013: Argument 3: type mismatch, expected dict but got list', 'E1206: Dictionary required for argument 3') enddef def Test_ch_canread() @@ -1126,6 +1128,16 @@ def Test_fullcommand() assert_equal('', fullcommand('scg')) enddef +def Test_funcref() + CheckDefAndScriptFailure2(['funcref("reverse", 2)'], 'E1013: Argument 2: type mismatch, expected list but got number', 'E1211: List required for argument 2') + CheckDefAndScriptFailure2(['funcref("reverse", [2], [1])'], 'E1013: Argument 3: type mismatch, expected dict but got list', 'E1206: Dictionary required for argument 3') +enddef + +def Test_function() + CheckDefAndScriptFailure2(['function("reverse", 2)'], 'E1013: Argument 2: type mismatch, expected list but got number', 'E1211: List required for argument 2') + CheckDefAndScriptFailure2(['function("reverse", [2], [1])'], 'E1013: Argument 3: type mismatch, expected dict but got list', 'E1206: Dictionary required for argument 3') +enddef + def Test_garbagecollect() garbagecollect(true) CheckDefAndScriptFailure2(['garbagecollect("1")'], 'E1013: Argument 1: type mismatch, expected bool but got string', 'E1135: Using a String as a Bool') @@ -1691,6 +1703,20 @@ def Test_keys_return_type() var->assert_equal(['a', 'b']) enddef +def Test_libcall() + CheckFeature libcall + CheckDefAndScriptFailure2(['libcall(1, "b", 3)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['libcall("a", 2, 3)'], 'E1013: Argument 2: type mismatch, expected string but got number', 'E1174: String required for argument 2') + CheckDefAndScriptFailure2(['libcall("a", "b", 1.1)'], 'E1013: Argument 3: type mismatch, expected string but got float', 'E1174: String required for argument 3') +enddef + +def Test_libcallnr() + CheckFeature libcall + CheckDefAndScriptFailure2(['libcallnr(1, "b", 3)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['libcallnr("a", 2, 3)'], 'E1013: Argument 2: type mismatch, expected string but got number', 'E1174: String required for argument 2') + CheckDefAndScriptFailure2(['libcallnr("a", "b", 1.1)'], 'E1013: Argument 3: type mismatch, expected string but got float', 'E1174: String required for argument 3') +enddef + def Test_line() assert_fails('line(true)', 'E1174:') CheckDefAndScriptFailure2(['line(1)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') @@ -1726,6 +1752,10 @@ def SID(): number ->str2nr() enddef +def Test_listener_add() + CheckDefAndScriptFailure2(['listener_add("1", true)'], 'E1013: Argument 2: type mismatch, expected string but got bool', 'E1174: String required for argument 2') +enddef + def Test_listener_flush() CheckDefAndScriptFailure2(['listener_flush([1])'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E730: Using a List as a String') enddef @@ -2285,8 +2315,15 @@ def Test_range() enddef def Test_readdir() - eval expand('sautest')->readdir((e) => e[0] !=# '.') - eval expand('sautest')->readdirex((e) => e.name[0] !=# '.') + eval expand('sautest')->readdir((e) => e[0] !=# '.') + eval expand('sautest')->readdirex((e) => e.name[0] !=# '.') + CheckDefAndScriptFailure2(['readdir(["a"])'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['readdir("a", "1", [3])'], 'E1013: Argument 3: type mismatch, expected dict but got list', 'E1206: Dictionary required for argument 3') +enddef + +def Test_readdirex() + CheckDefAndScriptFailure2(['readdirex(["a"])'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['readdirex("a", "1", [3])'], 'E1013: Argument 3: type mismatch, expected dict but got list', 'E1206: Dictionary required for argument 3') enddef def Test_readblob() @@ -2604,28 +2641,19 @@ def Test_searchpair() CheckScriptSuccess(lines) assert_equal('yes', g:caught) unlet g:caught + bwipe! lines =<< trim END echo searchpair("a", "b", "c", "d", "f", 33) END CheckDefAndScriptFailure2(lines, 'E1001: Variable not found: f', 'E475: Invalid argument: d') - lines =<< trim END - def TestPair() - echo searchpair("a", "b", "c", "d", "1", 99) - enddef - defcompile - END - CheckScriptSuccess(lines) - - bwipe! CheckDefAndScriptFailure2(['searchpair(1, "b", "c")'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') CheckDefAndScriptFailure2(['searchpair("a", 2, "c")'], 'E1013: Argument 2: type mismatch, expected string but got number', 'E1174: String required for argument 2') CheckDefAndScriptFailure2(['searchpair("a", "b", 3)'], 'E1013: Argument 3: type mismatch, expected string but got number', 'E1174: String required for argument 3') CheckDefAndScriptFailure2(['searchpair("a", "b", "c", 4)'], 'E1013: Argument 4: type mismatch, expected string but got number', 'E1174: String required for argument 4') - # BUG: Vim crashes with the following test - #CheckDefAndScriptFailure2(['searchpair("a", "b", "c", "d", "1", "f")'], 'E1013: Argument 4: type mismatch, expected string but got number', 'E1174: String required for argument 4') - #CheckDefAndScriptFailure2(['searchpair("a", "b", "c", "d", "1", 3, "g")'], 'E1013: Argument 4: type mismatch, expected string but got number', 'E1174: String required for argument 4') + CheckDefAndScriptFailure2(['searchpair("a", "b", "c", "r", "1", "f")'], 'E1013: Argument 6: type mismatch, expected number but got string', 'E1210: Number required for argument 6') + CheckDefAndScriptFailure2(['searchpair("a", "b", "c", "r", "1", 3, "g")'], 'E1013: Argument 7: type mismatch, expected number but got string', 'E1210: Number required for argument 7') enddef def Test_searchpos() @@ -2951,6 +2979,16 @@ def Test_spellsuggest() CheckDefAndScriptFailure2(['spellsuggest("a", 1, 0z01)'], 'E1013: Argument 3: type mismatch, expected bool but got blob', 'E1212: Bool required for argument 3') enddef +def Test_sound_playevent() + CheckFeature sound + CheckDefAndScriptFailure2(['sound_playevent(1)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') +enddef + +def Test_sound_playfile() + CheckFeature sound + CheckDefAndScriptFailure2(['sound_playfile(1)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') +enddef + def Test_sound_stop() CheckFeature sound CheckDefFailure(['sound_stop("x")'], 'E1013: Argument 1: type mismatch, expected number but got string') @@ -3137,6 +3175,9 @@ def Test_substitute() assert_fails('"text"->substitute(".*", () => job_start(":"), "")', 'E908: using an invalid value as a String: job') assert_fails('"text"->substitute(".*", () => job_start(":")->job_getchannel(), "")', 'E908: using an invalid value as a String: channel') endif + CheckDefAndScriptFailure2(['substitute(1, "b", "1", "d")'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['substitute("a", 2, "1", "d")'], 'E1013: Argument 2: type mismatch, expected string but got number', 'E1174: String required for argument 2') + CheckDefAndScriptFailure2(['substitute("a", "b", "1", 4)'], 'E1013: Argument 4: type mismatch, expected string but got number', 'E1174: String required for argument 4') enddef def Test_swapinfo() @@ -3376,6 +3417,14 @@ def Test_test_getvalue() CheckDefAndScriptFailure2(['test_getvalue(1.1)'], 'E1013: Argument 1: type mismatch, expected string but got float', 'E474: Invalid argument') enddef +def Test_test_gui_drop_files() + CheckGui + CheckDefAndScriptFailure2(['test_gui_drop_files("a", 1, 1, 0)'], 'E1013: Argument 1: type mismatch, expected list but got string', 'E1211: List required for argument 1') + CheckDefAndScriptFailure2(['test_gui_drop_files(["x"], "", 1, 0)'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2') + CheckDefAndScriptFailure2(['test_gui_drop_files(["x"], 1, "", 0)'], 'E1013: Argument 3: type mismatch, expected number but got string', 'E1210: Number required for argument 3') + CheckDefAndScriptFailure2(['test_gui_drop_files(["x"], 1, 1, "")'], 'E1013: Argument 4: type mismatch, expected number but got string', 'E1210: Number required for argument 4') +enddef + def Test_test_gui_mouse_event() CheckGui CheckDefAndScriptFailure2(['test_gui_mouse_event(1.1, 1, 1, 1, 1)'], 'E1013: Argument 1: type mismatch, expected number but got float', 'E1210: Number required for argument 1') @@ -3399,6 +3448,13 @@ def Test_test_override() CheckDefAndScriptFailure2(['test_override("a", "x")'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2') enddef +def Test_test_scrollbar() + CheckGui + CheckDefAndScriptFailure2(['test_scrollbar(1, 2, 3)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['test_scrollbar("a", "b", 3)'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2') + CheckDefAndScriptFailure2(['test_scrollbar("a", 2, "c")'], 'E1013: Argument 3: type mismatch, expected number but got string', 'E1210: Number required for argument 3') +enddef + def Test_test_setmouse() CheckDefAndScriptFailure2(['test_setmouse("a", 10)'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E474: Invalid argument') CheckDefAndScriptFailure2(['test_setmouse(10, "b")'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E474: Invalid argument') diff --git a/src/testing.c b/src/testing.c --- a/src/testing.c +++ b/src/testing.c @@ -1193,6 +1193,11 @@ f_test_scrollbar(typval_T *argvars, typv int dragging; scrollbar_T *sb = NULL; + if (check_for_string_arg(argvars, 0) == FAIL + || check_for_number_arg(argvars, 1) == FAIL + || check_for_number_arg(argvars, 2) == FAIL) + return; + if (argvars[0].v_type != VAR_STRING || (argvars[1].v_type) != VAR_NUMBER || (argvars[2].v_type) != VAR_NUMBER) @@ -1281,14 +1286,11 @@ f_test_gui_drop_files(typval_T *argvars list_T *l; listitem_T *li; - if (argvars[0].v_type != VAR_LIST - || (argvars[1].v_type) != VAR_NUMBER - || (argvars[2].v_type) != VAR_NUMBER - || (argvars[3].v_type) != VAR_NUMBER) - { - emsg(_(e_invarg)); + if (check_for_list_arg(argvars, 0) == FAIL + || check_for_number_arg(argvars, 1) == FAIL + || check_for_number_arg(argvars, 2) == FAIL + || check_for_number_arg(argvars, 3) == FAIL) return; - } row = tv_get_number(&argvars[1]); col = tv_get_number(&argvars[2]); diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -756,6 +756,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 3215, +/**/ 3214, /**/ 3213,