]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 8.2.3215: Vim9: argument types are not checked at compile time v8.2.3215
authorYegappan Lakshmanan <yegappan@yahoo.com>
Sat, 24 Jul 2021 19:33:26 +0000 (21:33 +0200)
committerBram Moolenaar <Bram@vim.org>
Sat, 24 Jul 2021 19:33:26 +0000 (21:33 +0200)
Problem:    Vim9: argument types are not checked at compile time.
Solution:   Add several more type checks. Sort the argument lists.
            (Yegappan Lakshmanan, closes #8626)

src/change.c
src/evalfunc.c
src/filepath.c
src/sound.c
src/testdir/test_gui.vim
src/testdir/test_vim9_builtin.vim
src/testing.c
src/version.c

index 73ea64ff197e70fb55eb57cb7d0997e2c9c35372..ee1bd6fca867daae742f48f3f56c1a3e9d365ed9 100644 (file)
@@ -241,6 +241,9 @@ f_listener_add(typval_T *argvars, typval_T *rettv)
     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;
index 22952d43ba466001a77f08a0f45ee8f528339219..518b3f4798ad9e0ecf9ebb4aef6c432053a90127 100644 (file)
@@ -644,83 +644,91 @@ arg_cursor1(type_T *type, argcontext_T *context)
 /*
  * 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_listblob_item[] = {arg_list_or_blob, arg_item_of_prev};
+static argcheck_T arg2_lnum[] = {arg_lnum, arg_lnum};
+static argcheck_T arg2_lnum_number[] = {arg_lnum, arg_number};
+static argcheck_T arg2_number[] = {arg_number, arg_number};
 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_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_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_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_string, arg_bool, arg_bool, arg_bool};
 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 arg2_mapfilter[] = {arg_list_or_dict_or_blob, NULL};
+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 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 *rettv)
     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, typval_T *rettv, int is_funcref)
     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, typval_T *rettv, int type)
     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 *rettv)
     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];
index 900c5bd69ca25828f8250758800b967766336da4..989f56e537a2263df7f588249ea8813d5f238b22 100644 (file)
@@ -1602,6 +1602,13 @@ f_readdir(typval_T *argvars, typval_T *rettv)
 
     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 *rettv)
 
     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];
 
index 702fd257a7d21b516856102418e69409835e7f02..f857c87255f75abc4f928a62c83484c0d7eff692 100644 (file)
@@ -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, typval_T *rettv)
 {
     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, typval_T *rettv)
     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;
index 237bfb4456be916effb544f78c3dc720dddbcdcb..c01151cc3f92d15efde724d724db7597f60f3a09 100644 (file)
@@ -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
index d42b3de9b4e693d5901cd9ed8db3fa155167a612..f2d6e641549bb2ff0b965afbd19d1f3c0330bff7 100644 (file)
@@ -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<any> but got number', 'E1211: List required for argument 2')
+  CheckDefAndScriptFailure2(['call("reverse", [2], [1])'], 'E1013: Argument 3: type mismatch, expected dict<any> but got list<number>', '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<any> but got number', 'E1211: List required for argument 2')
+  CheckDefAndScriptFailure2(['funcref("reverse", [2], [1])'], 'E1013: Argument 3: type mismatch, expected dict<any> but got list<number>', 'E1206: Dictionary required for argument 3')
+enddef
+
+def Test_function()
+  CheckDefAndScriptFailure2(['function("reverse", 2)'], 'E1013: Argument 2: type mismatch, expected list<any> but got number', 'E1211: List required for argument 2')
+  CheckDefAndScriptFailure2(['function("reverse", [2], [1])'], 'E1013: Argument 3: type mismatch, expected dict<any> but got list<number>', '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<number>', '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<string>', 'E1174: String required for argument 1')
+  CheckDefAndScriptFailure2(['readdir("a", "1", [3])'], 'E1013: Argument 3: type mismatch, expected dict<any> but got list<number>', 'E1206: Dictionary required for argument 3')
+enddef
+
+def Test_readdirex()
+  CheckDefAndScriptFailure2(['readdirex(["a"])'], 'E1013: Argument 1: type mismatch, expected string but got list<string>', 'E1174: String required for argument 1')
+  CheckDefAndScriptFailure2(['readdirex("a", "1", [3])'], 'E1013: Argument 3: type mismatch, expected dict<any> but got list<number>', '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<string> 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')
index 5b2f7af138769986d2e3e526feb927ff0879eca5..9f3c29422fd940a2989c115063e7feed3b895062 100644 (file)
@@ -1193,6 +1193,11 @@ f_test_scrollbar(typval_T *argvars, typval_T *rettv UNUSED)
     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 UNUSED, typval_T *rettv UNUSED)
     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]);
index a331760e1f649138e8ea948e6e55913639ff516a..f12b9dc04ec5b2e1b5c4982d217e63ca5f9870da 100644 (file)
@@ -755,6 +755,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    3215,
 /**/
     3214,
 /**/