]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 8.2.3173: Vim9: argument types are not checked at compile time v8.2.3173
authorYegappan Lakshmanan <yegappan@yahoo.com>
Sat, 17 Jul 2021 17:11:07 +0000 (19:11 +0200)
committerBram Moolenaar <Bram@vim.org>
Sat, 17 Jul 2021 17:11:07 +0000 (19:11 +0200)
Problem:    Vim9: argument types are not checked at compile time.
Solution:   Add more type checks. (Yegappan Lakshmanan, closes #8581)

src/diff.c
src/errors.h
src/evalfunc.c
src/globals.h
src/job.c
src/proto/typval.pro
src/strings.c
src/terminal.c
src/testdir/test_vim9_builtin.vim
src/typval.c
src/version.c

index 6f25c373c4f7e52bb061e589aa16b7cbd1695f61..4c8afb12bd3e1ada130355da7ed012928211a685 100644 (file)
@@ -3283,7 +3283,7 @@ f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
 f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
 {
 #ifdef FEAT_DIFF
-    linenr_T           lnum = tv_get_lnum(argvars);
+    linenr_T           lnum;
     static linenr_T    prev_lnum = 0;
     static varnumber_T changedtick = 0;
     static int         fnum = 0;
@@ -3293,6 +3293,14 @@ f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
     int                        filler_lines;
     int                        col;
 
+    if (in_vim9script()
+           && ((argvars[0].v_type != VAR_STRING
+                   && argvars[0].v_type != VAR_NUMBER
+                   && check_for_string_arg(argvars, 0) == FAIL)
+               || check_for_number_arg(argvars, 1) == FAIL))
+       return;
+
+    lnum = tv_get_lnum(argvars);
     if (lnum < 0)      // ignore type error in {lnum} arg
        lnum = 0;
     if (lnum != prev_lnum
index 09679b23acadb9d57dbf1bcd1e36b73b4733ef06..46de733bc63ade5229df5811be8e769485c68424 100644 (file)
@@ -502,3 +502,7 @@ EXTERN char e_invalid_value_for_line_number_str[]
        INIT(= N_("E1209: Invalid value for a line number: \"%s\""));
 EXTERN char e_number_required_for_argument_nr[]
        INIT(= N_("E1210: Number required for argument %d"));
+EXTERN char e_list_required_for_argument_nr[]
+       INIT(= N_("E1211: List required for argument %d"));
+EXTERN char e_bool_required_for_argument_nr[]
+       INIT(= N_("E1211: Bool required for argument %d"));
index dee1ecb0fcf0f7af40fdcc6570fbed918a445c82..2964d2391212fc3dff7e7f97b1f6921098a12f33 100644 (file)
@@ -499,9 +499,12 @@ static argcheck_T arg2_dict_string[] = {arg_dict_any, arg_string};
 static argcheck_T arg2_dict_string_or_nr[] = {arg_dict_any, arg_string_or_nr};
 static argcheck_T arg2_string_dict[] = {arg_string, arg_dict_any};
 static argcheck_T arg2_string_nr[] = {arg_string, arg_number};
+static argcheck_T arg2_string_bool[] = {arg_string, arg_bool};
 //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_string_or_list_dict[] = {arg_string_or_list_any, arg_dict_any};
+static argcheck_T arg2_string_or_nr_string[] = {arg_string_or_nr, arg_string};
+static argcheck_T arg2_string_or_nr_nr[] = {arg_string_or_nr, arg_number};
 static argcheck_T arg2_chan_or_job_dict[] = {arg_chan_or_job, arg_dict_any};
 static argcheck_T arg2_nr_dict_any[] = {arg_number, arg_dict_any};
 //static argcheck_T arg2_string_number[] = {arg_string, arg_number};
@@ -510,12 +513,13 @@ static argcheck_T arg3_number[] = {arg_number, arg_number, arg_number};
 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 arg2_execute[] = {arg_string_or_list_string, arg_string};
-static argcheck_T arg23_win_execute[] = {arg_number, arg_string_or_list_string, arg_string};
-static argcheck_T arg2_setline[] = {arg_string_or_nr, NULL};
-static argcheck_T arg3_setbufline[] = {arg_string_or_nr, arg_string_or_nr, arg_str_or_nr_or_list};
 static argcheck_T arg23_extend[] = {arg_list_or_dict, arg_same_as_prev, arg_extend3};
 static argcheck_T arg23_extendnew[] = {arg_list_or_dict, arg_same_struct_as_prev, arg_extend3};
 static argcheck_T arg3_insert[] = {arg_list_or_blob, arg_item_of_prev, arg_number};
+static argcheck_T arg3_setbufline[] = {arg_string_or_nr, arg_string_or_nr, arg_str_or_nr_or_list};
+static argcheck_T arg2_setline[] = {arg_string_or_nr, NULL};
+static argcheck_T arg23_win_execute[] = {arg_number, arg_string_or_list_string, arg_string};
+static argcheck_T arg4_match_func[] = {arg_string_or_list_any, arg_string, arg_number, arg_number};
 
 /*
  * Functions that return the return type of a builtin function.
@@ -931,7 +935,7 @@ static funcentry_T global_functions[] =
                        ret_string,         JOB_FUNC(f_ch_status)},
     {"changenr",       0, 0, 0,            NULL,
                        ret_number,         f_changenr},
-    {"char2nr",                1, 2, FEARG_1,      NULL,
+    {"char2nr",                1, 2, FEARG_1,      arg2_string_bool,
                        ret_number,         f_char2nr},
     {"charclass",      1, 1, FEARG_1,      arg1_string,
                        ret_number,         f_charclass},
@@ -987,7 +991,7 @@ static funcentry_T global_functions[] =
                        ret_number_bool,    f_did_filetype},
     {"diff_filler",    1, 1, FEARG_1,      arg1_string_or_nr,
                        ret_number,         f_diff_filler},
-    {"diff_hlID",      2, 2, FEARG_1,      NULL,
+    {"diff_hlID",      2, 2, FEARG_1,      arg2_string_or_nr_nr,
                        ret_number,         f_diff_hlID},
     {"echoraw",                1, 1, FEARG_1,      arg1_string,
                        ret_void,           f_echoraw},
@@ -1251,7 +1255,7 @@ static funcentry_T global_functions[] =
                        ret_string,         f_json_encode},
     {"keys",           1, 1, FEARG_1,      arg1_dict_any,
                        ret_list_string,    f_keys},
-    {"last_buffer_nr", 0, 0, 0,            arg1_string_or_nr,  // obsolete
+    {"last_buffer_nr", 0, 0, 0,            NULL,       // obsolete
                        ret_number,         f_last_buffer_nr},
     {"len",            1, 1, FEARG_1,      NULL,
                        ret_number,         f_len},
@@ -1297,7 +1301,7 @@ static funcentry_T global_functions[] =
                        ret_first_cont,     f_mapnew},
     {"mapset",         3, 3, FEARG_1,      NULL,
                        ret_void,           f_mapset},
-    {"match",          2, 4, FEARG_1,      NULL,
+    {"match",          2, 4, FEARG_1,      arg4_match_func,
                        ret_any,            f_match},
     {"matchadd",       2, 5, FEARG_1,      NULL,
                        ret_number,         f_matchadd},
@@ -1307,17 +1311,17 @@ static funcentry_T global_functions[] =
                        ret_list_string,    f_matcharg},
     {"matchdelete",    1, 2, FEARG_1,      arg2_number,
                        ret_number_bool,    f_matchdelete},
-    {"matchend",       2, 4, FEARG_1,      NULL,
+    {"matchend",       2, 4, FEARG_1,      arg4_match_func,
                        ret_number,         f_matchend},
     {"matchfuzzy",     2, 3, FEARG_1,      NULL,
                        ret_list_string,    f_matchfuzzy},
     {"matchfuzzypos",  2, 3, FEARG_1,      NULL,
                        ret_list_any,       f_matchfuzzypos},
-    {"matchlist",      2, 4, FEARG_1,      NULL,
+    {"matchlist",      2, 4, FEARG_1,      arg4_match_func,
                        ret_list_string,    f_matchlist},
-    {"matchstr",       2, 4, FEARG_1,      NULL,
+    {"matchstr",       2, 4, FEARG_1,      arg4_match_func,
                        ret_string,         f_matchstr},
-    {"matchstrpos",    2, 4, FEARG_1,      NULL,
+    {"matchstrpos",    2, 4, FEARG_1,      arg4_match_func,
                        ret_list_any,       f_matchstrpos},
     {"max",            1, 1, FEARG_1,      arg1_list_or_dict,
                        ret_number,         f_max},
@@ -1413,7 +1417,7 @@ static funcentry_T global_functions[] =
                        ret_void,           JOB_FUNC(f_prompt_setcallback)},
     {"prompt_setinterrupt", 2, 2, FEARG_1,  NULL,
                        ret_void,           JOB_FUNC(f_prompt_setinterrupt)},
-    {"prompt_setprompt", 2, 2, FEARG_1,            NULL,
+    {"prompt_setprompt", 2, 2, FEARG_1,            arg2_string_or_nr_string,
                        ret_void,           JOB_FUNC(f_prompt_setprompt)},
     {"prop_add",       3, 3, FEARG_1,      NULL,
                        ret_void,           PROP_FUNC(f_prop_add)},
@@ -1651,7 +1655,7 @@ static funcentry_T global_functions[] =
                        ret_string,         f_state},
     {"str2float",      1, 1, FEARG_1,      arg1_string,
                        ret_float,          FLOAT_FUNC(f_str2float)},
-    {"str2list",       1, 2, FEARG_1,      NULL,
+    {"str2list",       1, 2, FEARG_1,      arg2_string_bool,
                        ret_list_number,    f_str2list},
     {"str2nr",         1, 3, FEARG_1,      arg3_string_nr_bool,
                        ret_number,         f_str2nr},
@@ -1659,7 +1663,7 @@ static funcentry_T global_functions[] =
                        ret_number,         f_strcharlen},
     {"strcharpart",    2, 4, FEARG_1,      NULL,
                        ret_string,         f_strcharpart},
-    {"strchars",       1, 2, FEARG_1,      NULL,
+    {"strchars",       1, 2, FEARG_1,      arg2_string_bool,
                        ret_number,         f_strchars},
     {"strdisplaywidth",        1, 2, FEARG_1,      arg2_string_nr,
                        ret_number,         f_strdisplaywidth},
@@ -1709,9 +1713,9 @@ static funcentry_T global_functions[] =
                        ret_string,         f_synIDattr},
     {"synIDtrans",     1, 1, FEARG_1,      arg1_number,
                        ret_number,         f_synIDtrans},
-    {"synconcealed",   2, 2, 0,            NULL,
+    {"synconcealed",   2, 2, 0,            arg2_string_or_nr_nr,
                        ret_list_any,       f_synconcealed},
-    {"synstack",       2, 2, 0,            NULL,
+    {"synstack",       2, 2, 0,            arg2_string_or_nr_nr,
                        ret_list_number,    f_synstack},
     {"system",         1, 2, FEARG_1,      NULL,
                        ret_string,         f_system},
@@ -1771,7 +1775,7 @@ static funcentry_T global_functions[] =
                        ret_list_number,    TERM_FUNC(f_term_list)},
     {"term_scrape",    2, 2, FEARG_1,      NULL,
                        ret_list_dict_any,  TERM_FUNC(f_term_scrape)},
-    {"term_sendkeys",  2, 2, FEARG_1,      NULL,
+    {"term_sendkeys",  2, 2, FEARG_1,      arg2_string_or_nr_string,
                        ret_void,           TERM_FUNC(f_term_sendkeys)},
     {"term_setansicolors", 2, 2, FEARG_1,   NULL,
                        ret_void,
@@ -1781,17 +1785,17 @@ static funcentry_T global_functions[] =
            NULL
 #endif
                        },
-    {"term_setapi",    2, 2, FEARG_1,      NULL,
+    {"term_setapi",    2, 2, FEARG_1,      arg2_string_or_nr_string,
                        ret_void,           TERM_FUNC(f_term_setapi)},
-    {"term_setkill",   2, 2, FEARG_1,      NULL,
+    {"term_setkill",   2, 2, FEARG_1,      arg2_string_or_nr_string,
                        ret_void,           TERM_FUNC(f_term_setkill)},
-    {"term_setrestore",        2, 2, FEARG_1,      NULL,
+    {"term_setrestore",        2, 2, FEARG_1,      arg2_string_or_nr_string,
                        ret_void,           TERM_FUNC(f_term_setrestore)},
     {"term_setsize",   3, 3, FEARG_1,      NULL,
                        ret_void,           TERM_FUNC(f_term_setsize)},
     {"term_start",     1, 2, FEARG_1,      NULL,
                        ret_number,         TERM_FUNC(f_term_start)},
-    {"term_wait",      1, 2, FEARG_1,      NULL,
+    {"term_wait",      1, 2, FEARG_1,      arg2_string_or_nr_nr,
                        ret_void,           TERM_FUNC(f_term_wait)},
     {"terminalprops",  0, 0, 0,            NULL,
                        ret_dict_string,    f_terminalprops},
@@ -2473,8 +2477,12 @@ f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
     static void
 f_char2nr(typval_T *argvars, typval_T *rettv)
 {
-    if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
+    if (in_vim9script()
+           && (check_for_string_arg(argvars, 0) == FAIL
+               || (argvars[1].v_type != VAR_UNKNOWN
+                   && check_for_bool_arg(argvars, 1) == FAIL)))
        return;
+
     if (has_mbyte)
     {
        int     utf8 = 0;
@@ -6304,6 +6312,17 @@ find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
        rettv->vval.v_string = NULL;
     }
 
+    if (in_vim9script()
+           && ((argvars[0].v_type != VAR_STRING
+                   && argvars[0].v_type != VAR_LIST
+                   && check_for_string_arg(argvars, 0) == FAIL)
+               || (check_for_string_arg(argvars, 1) == FAIL)
+               || (argvars[2].v_type != VAR_UNKNOWN
+                   && (check_for_number_arg(argvars, 2) == FAIL
+                       || (argvars[3].v_type != VAR_UNKNOWN
+                           && check_for_number_arg(argvars, 3) == FAIL)))))
+       goto theend;
+
     if (argvars[0].v_type == VAR_LIST)
     {
        if ((l = argvars[0].vval.v_list) == NULL)
@@ -8961,6 +8980,13 @@ f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
 
     rettv_list_set(rettv, NULL);
 
+    if (in_vim9script()
+           && ((argvars[0].v_type != VAR_STRING
+                   && argvars[0].v_type != VAR_NUMBER
+                   && check_for_string_arg(argvars, 0) == FAIL)
+               || check_for_number_arg(argvars, 1) == FAIL))
+       return;
+
 #if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
     lnum = tv_get_lnum(argvars);               // -1 on type error
     col = (colnr_T)tv_get_number(&argvars[1]) - 1;     // -1 on type error
@@ -9017,6 +9043,13 @@ f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
 
     rettv_list_set(rettv, NULL);
 
+    if (in_vim9script()
+           && ((argvars[0].v_type != VAR_STRING
+                   && argvars[0].v_type != VAR_NUMBER
+                   && check_for_string_arg(argvars, 0) == FAIL)
+               || check_for_number_arg(argvars, 1) == FAIL))
+       return;
+
 #ifdef FEAT_SYN_HL
     lnum = tv_get_lnum(argvars);               // -1 on type error
     col = (colnr_T)tv_get_number(&argvars[1]) - 1;     // -1 on type error
index e486b6ea1367dac1de0252b27ef3b7ffae933e57..7829f2a4e2675507b206a5248f39361f4de5ff1f 100644 (file)
@@ -1699,6 +1699,7 @@ EXTERN char e_readonlyvar[]       INIT(= N_("E46: Cannot change read-only variable \"%
 EXTERN char e_readonlysbx[]    INIT(= N_("E794: Cannot set variable in the sandbox: \"%s\""));
 EXTERN char e_stringreq[]      INIT(= N_("E928: String required"));
 EXTERN char e_numberreq[]      INIT(= N_("E889: Number required"));
+EXTERN char e_boolreq[]                INIT(= N_("E839: Number required"));
 EXTERN char e_emptykey[]       INIT(= N_("E713: Cannot use empty key for Dictionary"));
 EXTERN char e_dictreq[]                INIT(= N_("E715: Dictionary required"));
 EXTERN char e_listidx[]                INIT(= N_("E684: list index out of range: %ld"));
index 189c06eb6e0da2109e2f94e653ad1148c24462e0..1271c779dad78ddc9ef44576689f05de40f2417f 100644 (file)
--- a/src/job.c
+++ b/src/job.c
@@ -1725,6 +1725,13 @@ f_prompt_setprompt(typval_T *argvars, typval_T *rettv UNUSED)
     buf_T      *buf;
     char_u     *text;
 
+    if (in_vim9script()
+           && ((argvars[0].v_type != VAR_STRING
+                   && argvars[0].v_type != VAR_NUMBER
+                   && check_for_string_arg(argvars, 0) == FAIL)
+               || check_for_string_arg(argvars, 1) == FAIL))
+       return;
+
     if (check_secure())
        return;
     buf = tv_get_buf(&argvars[0], FALSE);
index b1864bca0dd90a2a2b6a0415439eb422df5d97aa..ccde9a6b68e03d026824bd7e2db28d88d2da8631 100644 (file)
@@ -12,6 +12,8 @@ float_T tv_get_float(typval_T *varp);
 int check_for_string_arg(typval_T *args, int idx);
 int check_for_nonempty_string_arg(typval_T *args, int idx);
 int check_for_number_arg(typval_T *args, int idx);
+int check_for_bool_arg(typval_T *args, int idx);
+int check_for_list_arg(typval_T *args, int idx);
 int check_for_dict_arg(typval_T *args, int idx);
 char_u *tv_get_string(typval_T *varp);
 char_u *tv_get_string_strict(typval_T *varp);
index a87922d4699df9b037f9af78095e74b4c3cca794..98d420c6aa878e472bf233bbfc4d4813d21f327c 100644 (file)
@@ -902,6 +902,12 @@ f_str2list(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_bool_arg(argvars, 1) == FAIL)))
+       return;
+
     if (argvars[1].v_type != VAR_UNKNOWN)
        utf8 = (int)tv_get_bool_chk(&argvars[1], NULL);
 
@@ -1108,6 +1114,12 @@ f_strchars(typval_T *argvars, typval_T *rettv)
 {
     varnumber_T                skipcc = FALSE;
 
+    if (in_vim9script()
+           && (check_for_string_arg(argvars, 0) == FAIL
+               || (argvars[1].v_type != VAR_UNKNOWN
+                   && check_for_bool_arg(argvars, 1) == FAIL)))
+       return;
+
     if (argvars[1].v_type != VAR_UNKNOWN)
        skipcc = tv_get_bool(&argvars[1]);
     if (skipcc < 0 || skipcc > 1)
index 9db04756d67d6a6509250d334bcb7a422e85e18b..52645643b55a50100dcae8dce1c0c73219c13e36 100644 (file)
@@ -6093,10 +6093,18 @@ f_term_scrape(typval_T *argvars, typval_T *rettv)
     void
 f_term_sendkeys(typval_T *argvars, typval_T *rettv UNUSED)
 {
-    buf_T      *buf = term_get_buf(argvars, "term_sendkeys()");
+    buf_T      *buf;
     char_u     *msg;
     term_T     *term;
 
+    if (in_vim9script()
+           && ((argvars[0].v_type != VAR_STRING
+                   && argvars[0].v_type != VAR_NUMBER
+                   && check_for_string_arg(argvars, 0) == FAIL)
+               || check_for_string_arg(argvars, 1) == FAIL))
+       return;
+
+    buf = term_get_buf(argvars, "term_sendkeys()");
     if (buf == NULL)
        return;
 
@@ -6193,10 +6201,18 @@ f_term_setansicolors(typval_T *argvars, typval_T *rettv UNUSED)
     void
 f_term_setapi(typval_T *argvars, typval_T *rettv UNUSED)
 {
-    buf_T      *buf = term_get_buf(argvars, "term_setapi()");
+    buf_T      *buf;
     term_T     *term;
     char_u     *api;
 
+    if (in_vim9script()
+           && ((argvars[0].v_type != VAR_STRING
+                   && argvars[0].v_type != VAR_NUMBER
+                   && check_for_string_arg(argvars, 0) == FAIL)
+               || check_for_string_arg(argvars, 1) == FAIL))
+       return;
+
+    buf = term_get_buf(argvars, "term_setapi()");
     if (buf == NULL)
        return;
     term = buf->b_term;
@@ -6215,10 +6231,18 @@ f_term_setapi(typval_T *argvars, typval_T *rettv UNUSED)
 f_term_setrestore(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
 {
 #if defined(FEAT_SESSION)
-    buf_T      *buf = term_get_buf(argvars, "term_setrestore()");
+    buf_T      *buf;
     term_T     *term;
     char_u     *cmd;
 
+    if (in_vim9script()
+           && ((argvars[0].v_type != VAR_STRING
+                   && argvars[0].v_type != VAR_NUMBER
+                   && check_for_string_arg(argvars, 0) == FAIL)
+               || check_for_string_arg(argvars, 1) == FAIL))
+       return;
+
+    buf = term_get_buf(argvars, "term_setrestore()");
     if (buf == NULL)
        return;
     term = buf->b_term;
@@ -6237,10 +6261,18 @@ f_term_setrestore(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
     void
 f_term_setkill(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
 {
-    buf_T      *buf = term_get_buf(argvars, "term_setkill()");
+    buf_T      *buf;
     term_T     *term;
     char_u     *how;
 
+    if (in_vim9script()
+           && ((argvars[0].v_type != VAR_STRING
+                   && argvars[0].v_type != VAR_NUMBER
+                   && check_for_string_arg(argvars, 0) == FAIL)
+               || check_for_string_arg(argvars, 1) == FAIL))
+       return;
+
+    buf = term_get_buf(argvars, "term_setkill()");
     if (buf == NULL)
        return;
     term = buf->b_term;
@@ -6286,8 +6318,17 @@ f_term_start(typval_T *argvars, typval_T *rettv)
     void
 f_term_wait(typval_T *argvars, typval_T *rettv UNUSED)
 {
-    buf_T      *buf = term_get_buf(argvars, "term_wait()");
+    buf_T      *buf;
+
+    if (in_vim9script()
+           && ((argvars[0].v_type != VAR_STRING
+                   && argvars[0].v_type != VAR_NUMBER
+                   && check_for_string_arg(argvars, 0) == FAIL) ||
+               (argvars[1].v_type != VAR_UNKNOWN
+                && check_for_number_arg(argvars, 1) == FAIL)))
+       return;
 
+    buf = term_get_buf(argvars, "term_wait()");
     if (buf == NULL)
        return;
     if (buf->b_term->tl_job == NULL)
index 98ed85fb325e5d63b300c6b31403290044cad27e..0668797386e1d150341905d12ebabccdf2abeb87 100644 (file)
@@ -473,6 +473,12 @@ def Test_char2nr()
   char2nr('あ', true)->assert_equal(12354)
 
   assert_fails('char2nr(true)', 'E1174:')
+  CheckDefAndScriptFailure2(['char2nr(10)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1')
+  CheckDefAndScriptFailure2(['char2nr("a", 2)'], 'E1013: Argument 2: type mismatch, expected bool but got number', 'E1211: Bool required for argument 2')
+  assert_equal(97, char2nr('a', 1))
+  assert_equal(97, char2nr('a', 0))
+  assert_equal(97, char2nr('a', true))
+  assert_equal(97, char2nr('a', false))
 enddef
 
 def Test_charclass()
@@ -602,6 +608,11 @@ def Test_diff_filler()
   assert_equal(0, diff_filler('.'))
 enddef
 
+def Test_diff_hlID()
+  CheckDefAndScriptFailure2(['diff_hlID(0z10, 1)'], 'E1013: Argument 1: type mismatch, expected string but got blob', 'E1174: String required for argument 1')
+  CheckDefAndScriptFailure2(['diff_hlID(1, "a")'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2')
+enddef
+
 def Test_echoraw()
   CheckDefAndScriptFailure2(['echoraw(1)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1')
   CheckDefAndScriptFailure2(['echoraw(["x"])'], 'E1013: Argument 1: type mismatch, expected string but got list<string>', 'E1174: String required for argument 1')
@@ -1599,6 +1610,21 @@ def Test_map_failure()
   delete('Xtmpfile')
 enddef
 
+def Test_match()
+  CheckDefAndScriptFailure2(['match(0z12, "p")'], 'E1013: Argument 1: type mismatch, expected string but got blob', 'E1174: String required for argument 1')
+  CheckDefAndScriptFailure2(['match(["s"], [2])'], 'E1013: Argument 2: type mismatch, expected string but got list<number>', 'E1174: String required for argument 2')
+  CheckDefAndScriptFailure2(['match("s", "p", "q")'], 'E1013: Argument 3: type mismatch, expected number but got string', 'E1210: Number required for argument 3')
+  CheckDefAndScriptFailure2(['match("s", "p", 1, "r")'], 'E1013: Argument 4: type mismatch, expected number but got string', 'E1210: Number required for argument 4')
+  assert_equal(2, match('ab12cd', '12'))
+  assert_equal(-1, match('ab12cd', '34'))
+  assert_equal(6, match('ab12cd12ef', '12', 4))
+  assert_equal(2, match('abcd', '..', 0, 3))
+  assert_equal(1, match(['a', 'b', 'c'], 'b'))
+  assert_equal(-1, match(['a', 'b', 'c'], 'd'))
+  assert_equal(3, match(['a', 'b', 'c', 'b', 'd', 'b'], 'b', 2))
+  assert_equal(5, match(['a', 'b', 'c', 'b', 'd', 'b'], 'b', 2, 2))
+enddef
+
 def Test_matcharg()
   CheckDefFailure(['matcharg("x")'], 'E1013: Argument 1: type mismatch, expected number but got string')
 enddef
@@ -1609,6 +1635,71 @@ def Test_matchdelete()
   CheckDefFailure(['matchdelete(1, "x")'], 'E1013: Argument 2: type mismatch, expected number but got string')
 enddef
 
+def Test_matchend()
+  CheckDefAndScriptFailure2(['matchend(0z12, "p")'], 'E1013: Argument 1: type mismatch, expected string but got blob', 'E1174: String required for argument 1')
+  CheckDefAndScriptFailure2(['matchend(["s"], [2])'], 'E1013: Argument 2: type mismatch, expected string but got list<number>', 'E1174: String required for argument 2')
+  CheckDefAndScriptFailure2(['matchend("s", "p", "q")'], 'E1013: Argument 3: type mismatch, expected number but got string', 'E1210: Number required for argument 3')
+  CheckDefAndScriptFailure2(['matchend("s", "p", 1, "r")'], 'E1013: Argument 4: type mismatch, expected number but got string', 'E1210: Number required for argument 4')
+  assert_equal(4, matchend('ab12cd', '12'))
+  assert_equal(-1, matchend('ab12cd', '34'))
+  assert_equal(8, matchend('ab12cd12ef', '12', 4))
+  assert_equal(4, matchend('abcd', '..', 0, 3))
+  assert_equal(1, matchend(['a', 'b', 'c'], 'b'))
+  assert_equal(-1, matchend(['a', 'b', 'c'], 'd'))
+  assert_equal(3, matchend(['a', 'b', 'c', 'b', 'd', 'b'], 'b', 2))
+  assert_equal(5, matchend(['a', 'b', 'c', 'b', 'd', 'b'], 'b', 2, 2))
+enddef
+
+def Test_matchlist()
+  CheckDefAndScriptFailure2(['matchlist(0z12, "p")'], 'E1013: Argument 1: type mismatch, expected string but got blob', 'E1174: String required for argument 1')
+  CheckDefAndScriptFailure2(['matchlist(["s"], [2])'], 'E1013: Argument 2: type mismatch, expected string but got list<number>', 'E1174: String required for argument 2')
+  CheckDefAndScriptFailure2(['matchlist("s", "p", "q")'], 'E1013: Argument 3: type mismatch, expected number but got string', 'E1210: Number required for argument 3')
+  CheckDefAndScriptFailure2(['matchlist("s", "p", 1, "r")'], 'E1013: Argument 4: type mismatch, expected number but got string', 'E1210: Number required for argument 4')
+  var l: list<string> = ['12',  '', '', '', '', '', '', '', '', '']
+  assert_equal(l, matchlist('ab12cd', '12'))
+  assert_equal([], matchlist('ab12cd', '34'))
+  assert_equal(l, matchlist('ab12cd12ef', '12', 4))
+  l[0] = 'cd'
+  assert_equal(l, matchlist('abcd', '..', 0, 3))
+  l[0] = 'b'
+  assert_equal(l, matchlist(['a', 'b', 'c'], 'b'))
+  assert_equal([], matchlist(['a', 'b', 'c'], 'd'))
+  assert_equal(l, matchlist(['a', 'b', 'c', 'b', 'd', 'b'], 'b', 2))
+  assert_equal(l, matchlist(['a', 'b', 'c', 'b', 'd', 'b'], 'b', 2, 2))
+enddef
+
+def Test_matchstr()
+  CheckDefAndScriptFailure2(['matchstr(0z12, "p")'], 'E1013: Argument 1: type mismatch, expected string but got blob', 'E1174: String required for argument 1')
+  CheckDefAndScriptFailure2(['matchstr(["s"], [2])'], 'E1013: Argument 2: type mismatch, expected string but got list<number>', 'E1174: String required for argument 2')
+  CheckDefAndScriptFailure2(['matchstr("s", "p", "q")'], 'E1013: Argument 3: type mismatch, expected number but got string', 'E1210: Number required for argument 3')
+  CheckDefAndScriptFailure2(['matchstr("s", "p", 1, "r")'], 'E1013: Argument 4: type mismatch, expected number but got string', 'E1210: Number required for argument 4')
+  assert_equal('12', matchstr('ab12cd', '12'))
+  assert_equal('', matchstr('ab12cd', '34'))
+  assert_equal('12', matchstr('ab12cd12ef', '12', 4))
+  assert_equal('cd', matchstr('abcd', '..', 0, 3))
+  assert_equal('b', matchstr(['a', 'b', 'c'], 'b'))
+  assert_equal('', matchstr(['a', 'b', 'c'], 'd'))
+  assert_equal('b', matchstr(['a', 'b', 'c', 'b', 'd', 'b'], 'b', 2))
+  assert_equal('b', matchstr(['a', 'b', 'c', 'b', 'd', 'b'], 'b', 2, 2))
+enddef
+
+def Test_matchstrpos()
+  CheckDefAndScriptFailure2(['matchstrpos(0z12, "p")'], 'E1013: Argument 1: type mismatch, expected string but got blob', 'E1174: String required for argument 1')
+  CheckDefAndScriptFailure2(['matchstrpos(["s"], [2])'], 'E1013: Argument 2: type mismatch, expected string but got list<number>', 'E1174: String required for argument 2')
+  CheckDefAndScriptFailure2(['matchstrpos("s", "p", "q")'], 'E1013: Argument 3: type mismatch, expected number but got string', 'E1210: Number required for argument 3')
+  CheckDefAndScriptFailure2(['matchstrpos("s", "p", 1, "r")'], 'E1013: Argument 4: type mismatch, expected number but got string', 'E1210: Number required for argument 4')
+  assert_equal(['12', 2, 4], matchstrpos('ab12cd', '12'))
+  assert_equal(['', -1, -1], matchstrpos('ab12cd', '34'))
+  assert_equal(['12', 6, 8], matchstrpos('ab12cd12ef', '12', 4))
+  assert_equal(['cd', 2, 4], matchstrpos('abcd', '..', 0, 3))
+  assert_equal(['b', 1, 0, 1], matchstrpos(['a', 'b', 'c'], 'b'))
+  assert_equal(['', -1, -1, -1], matchstrpos(['a', 'b', 'c'], 'd'))
+  assert_equal(['b', 3, 0, 1],
+                    matchstrpos(['a', 'b', 'c', 'b', 'd', 'b'], 'b', 2))
+  assert_equal(['b', 5, 0, 1],
+                    matchstrpos(['a', 'b', 'c', 'b', 'd', 'b'], 'b', 2, 2))
+enddef
+
 def Test_max()
   g:flag = true
   var l1: list<number> = g:flag
@@ -1792,6 +1883,14 @@ def Test_prompt_getprompt()
   endif
 enddef
 
+def Test_prompt_setprompt()
+  if !has('channel')
+    CheckFeature channel
+  endif
+  CheckDefAndScriptFailure2(['prompt_setprompt([], "p")'], 'E1013: Argument 1: type mismatch, expected string but got list<unknown>', 'E1174: String required for argument 1')
+  CheckDefAndScriptFailure2(['prompt_setprompt(1, [])'], 'E1013: Argument 2: type mismatch, expected string but got list<unknown>', 'E1174: String required for argument 2')
+enddef
+
 def Test_prop_find()
   CheckDefAndScriptFailure2(['prop_find([1, 2])'], 'E1013: Argument 1: type mismatch, expected dict<any> but got list<number>', 'E715: Dictionary required')
   CheckDefAndScriptFailure2(['prop_find([1, 2], "k")'], 'E1013: Argument 1: type mismatch, expected dict<any> but got list<number>', 'E715: Dictionary required')
@@ -2407,6 +2506,14 @@ def Run_str2float()
   endif
 enddef
 
+def Test_str2list()
+  CheckDefAndScriptFailure2(['str2list(10)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1')
+  CheckDefAndScriptFailure2(['str2list("a", 2)'], 'E1013: Argument 2: type mismatch, expected bool but got number', 'E1211: Bool required for argument 2')
+  assert_equal([97], str2list('a'))
+  assert_equal([97], str2list('a', 1))
+  assert_equal([97], str2list('a', true))
+enddef
+
 def Test_str2nr()
   str2nr("1'000'000", 10, true)->assert_equal(1000000)
 
@@ -2426,6 +2533,11 @@ enddef
 
 def Test_strchars()
   strchars("A\u20dd", true)->assert_equal(1)
+  CheckDefAndScriptFailure2(['strchars(10)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1')
+  CheckDefAndScriptFailure2(['strchars("a", 2)'], 'E1013: Argument 2: type mismatch, expected bool but got number', 'E1211: Bool required for argument 2')
+  assert_equal(3, strchars('abc'))
+  assert_equal(3, strchars('abc', 1))
+  assert_equal(3, strchars('abc', true))
 enddef
 
 def Test_strdisplaywidth()
@@ -2521,6 +2633,16 @@ def Test_synIDtrans()
   CheckDefFailure(['synIDtrans("a")'], 'E1013: Argument 1: type mismatch, expected number but got string')
 enddef
 
+def Test_synconcealed()
+  CheckDefAndScriptFailure2(['synconcealed(0z10, 1)'], 'E1013: Argument 1: type mismatch, expected string but got blob', 'E1174: String required for argument 1')
+  CheckDefAndScriptFailure2(['synconcealed(1, "a")'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2')
+enddef
+
+def Test_synstack()
+  CheckDefAndScriptFailure2(['synstack(0z10, 1)'], 'E1013: Argument 1: type mismatch, expected string but got blob', 'E1174: String required for argument 1')
+  CheckDefAndScriptFailure2(['synstack(1, "a")'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2')
+enddef
+
 def Test_tabpagebuflist()
   CheckDefFailure(['tabpagebuflist("t")'], 'E1013: Argument 1: type mismatch, expected number but got string')
   assert_equal([bufnr('')], tabpagebuflist())
@@ -2607,6 +2729,29 @@ def Test_term_gettty()
   endif
 enddef
 
+def Test_term_sendkeys()
+  CheckRunVimInTerminal
+  CheckDefAndScriptFailure2(['term_sendkeys([], "p")'], 'E1013: Argument 1: type mismatch, expected string but got list<unknown>', 'E1174: String required for argument 1')
+  CheckDefAndScriptFailure2(['term_sendkeys(1, [])'], 'E1013: Argument 2: type mismatch, expected string but got list<unknown>', 'E1174: String required for argument 2')
+enddef
+
+def Test_term_setapi()
+  CheckRunVimInTerminal
+  CheckDefAndScriptFailure2(['term_setapi([], "p")'], 'E1013: Argument 1: type mismatch, expected string but got list<unknown>', 'E1174: String required for argument 1')
+  CheckDefAndScriptFailure2(['term_setapi(1, [])'], 'E1013: Argument 2: type mismatch, expected string but got list<unknown>', 'E1174: String required for argument 2')
+enddef
+
+def Test_term_setkill()
+  CheckRunVimInTerminal
+  CheckDefAndScriptFailure2(['term_setkill([], "p")'], 'E1013: Argument 1: type mismatch, expected string but got list<unknown>', 'E1174: String required for argument 1')
+  CheckDefAndScriptFailure2(['term_setkill(1, [])'], 'E1013: Argument 2: type mismatch, expected string but got list<unknown>', 'E1174: String required for argument 2')
+enddef
+
+def Test_term_setrestore()
+  CheckRunVimInTerminal
+  CheckDefAndScriptFailure2(['term_setrestore([], "p")'], 'E1013: Argument 1: type mismatch, expected string but got list<unknown>', 'E1174: String required for argument 1')
+  CheckDefAndScriptFailure2(['term_setrestore(1, [])'], 'E1013: Argument 2: type mismatch, expected string but got list<unknown>', 'E1174: String required for argument 2')
+enddef
 def Test_term_start()
   if !has('terminal')
     MissingFeature 'terminal'
@@ -2619,6 +2764,12 @@ def Test_term_start()
   endif
 enddef
 
+def Test_term_wait()
+  CheckRunVimInTerminal
+  CheckDefAndScriptFailure2(['term_wait(0z10, 1)'], 'E1013: Argument 1: type mismatch, expected string but got blob', 'E1174: String required for argument 1')
+  CheckDefAndScriptFailure2(['term_wait(1, "a")'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2')
+enddef
+
 def Test_test_alloc_fail()
   CheckDefAndScriptFailure2(['test_alloc_fail("a", 10, 20)'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E474: Invalid argument')
   CheckDefAndScriptFailure2(['test_alloc_fail(10, "b", 20)'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E474: Invalid argument')
index 6e0b528e7992c8fa190847fa557afafbc16f4727..03891c806dec356bd4454bc5b4ceb9a03aef438d 100644 (file)
@@ -352,7 +352,7 @@ tv_get_float(typval_T *varp)
 #endif
 
 /*
- * Give an error and return FAIL unless "tv" is a string.
+ * Give an error and return FAIL unless "args[idx]" is a string.
  */
     int
 check_for_string_arg(typval_T *args, int idx)
@@ -385,7 +385,7 @@ check_for_nonempty_string_arg(typval_T *args, int idx)
 }
 
 /*
- * Give an error and return FAIL unless "tv" is a number.
+ * Give an error and return FAIL unless "args[idx]" is a number.
  */
     int
 check_for_number_arg(typval_T *args, int idx)
@@ -402,7 +402,44 @@ check_for_number_arg(typval_T *args, int idx)
 }
 
 /*
- * Give an error and return FAIL unless "tv" is a dict.
+ * Give an error and return FAIL unless "args[idx]" is a bool.
+ */
+    int
+check_for_bool_arg(typval_T *args, int idx)
+{
+    if (args[idx].v_type != VAR_BOOL
+           && !(args[idx].v_type == VAR_NUMBER
+               && (args[idx].vval.v_number == 0
+                   || args[idx].vval.v_number == 1)))
+    {
+       if (idx >= 0)
+           semsg(_(e_bool_required_for_argument_nr), idx + 1);
+       else
+           emsg(_(e_boolreq));
+       return FAIL;
+    }
+    return OK;
+}
+
+/*
+ * Give an error and return FAIL unless "args[idx]" is a list.
+ */
+    int
+check_for_list_arg(typval_T *args, int idx)
+{
+    if (args[idx].v_type != VAR_LIST)
+    {
+       if (idx >= 0)
+           semsg(_(e_list_required_for_argument_nr), idx + 1);
+       else
+           emsg(_(e_listreq));
+       return FAIL;
+    }
+    return OK;
+}
+
+/*
+ * Give an error and return FAIL unless "args[idx]" is a dict.
  */
     int
 check_for_dict_arg(typval_T *args, int idx)
index 78d6088e413f7bd1c801347a76e05fe0d34c1731..f7e2c17a0a0c260c51f2bc22cbb0c9859460c931 100644 (file)
@@ -755,6 +755,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    3173,
 /**/
     3172,
 /**/