]> granicus.if.org Git - vim/commitdiff
patch 8.2.3221: Vim9: argument types are not checked at compile time v8.2.3221
authorYegappan Lakshmanan <yegappan@yahoo.com>
Sun, 25 Jul 2021 13:57:32 +0000 (15:57 +0200)
committerBram Moolenaar <Bram@vim.org>
Sun, 25 Jul 2021 13:57:32 +0000 (15:57 +0200)
Problem:    Vim9: argument types are not checked at compile time.
Solution:   Add several more type checks. (Yegappan Lakshmanan, closes #8632)

src/evalfunc.c
src/popupwin.c
src/proto/typval.pro
src/testdir/test_assert.vim
src/testdir/test_vim9_builtin.vim
src/testdir/test_vim9_script.vim
src/testing.c
src/typval.c
src/version.c

index 518b3f4798ad9e0ecf9ebb4aef6c432053a90127..1091e562a3db53d9c48679b920faaf2a26ac1501 100644 (file)
@@ -557,6 +557,44 @@ arg_extend3(type_T *type, argcontext_T *context)
     return OK;
 }
 
+/*
+ * Check "type" which is the first argument of get() (blob or list or dict or
+ * funcref)
+ */
+    static int
+arg_get1(type_T *type, argcontext_T *context)
+{
+    if (type->tt_type == VAR_ANY
+           || type->tt_type == VAR_BLOB
+           || type->tt_type == VAR_LIST
+           || type->tt_type == VAR_DICT
+           || type->tt_type == VAR_FUNC
+           || type->tt_type == VAR_PARTIAL)
+       return OK;
+
+    arg_type_mismatch(&t_list_any, type, context->arg_idx + 1);
+    return FAIL;
+}
+
+/*
+ * Check "type" which is the first argument of len() (number or string or
+ * blob or list or dict)
+ */
+    static int
+arg_len1(type_T *type, argcontext_T *context)
+{
+    if (type->tt_type == VAR_ANY
+           || type->tt_type == VAR_STRING
+           || type->tt_type == VAR_NUMBER
+           || type->tt_type == VAR_BLOB
+           || type->tt_type == VAR_LIST
+           || type->tt_type == VAR_DICT)
+       return OK;
+
+    arg_type_mismatch(&t_list_any, type, context->arg_idx + 1);
+    return FAIL;
+}
+
 /*
  * Check "type" which is the second argument of remove() (number or string or
  * any)
@@ -685,6 +723,7 @@ 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_any[] = {arg_number, NULL};
 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};
@@ -716,6 +755,7 @@ static argcheck_T arg3_number_string_buffer[] = {arg_number, arg_string, arg_buf
 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_any_string[] = {arg_string, NULL, arg_string};
 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_string_number_bool[] = {arg_string, arg_number, arg_bool};
@@ -729,6 +769,8 @@ static argcheck_T arg4_string_string_any_string[] = {arg_string, arg_string, NUL
 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 arg15_assert_fails[] = {arg_string_or_nr, arg_string_or_list_any, NULL, arg_number, arg_string};
+static argcheck_T arg34_assert_inrange[] = {arg_float_or_nr, arg_float_or_nr, arg_float_or_nr, arg_string};
 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};
@@ -738,15 +780,18 @@ static argcheck_T arg12_deepcopy[] = {NULL, arg_bool};
 static argcheck_T arg12_execute[] = {arg_string_or_list_string, arg_string};
 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 arg23_get[] = {arg_get1, arg_string_or_nr, NULL};
 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 arg1_len[] = {arg_len1};
 static argcheck_T arg3_libcall[] = {arg_string, arg_string, arg_string_or_nr};
 static argcheck_T arg14_maparg[] = {arg_string, arg_string, arg_bool, arg_bool};
 static argcheck_T arg2_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 arg119_printf[] = {arg_string_or_nr, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
 static argcheck_T arg23_reduce[] = {arg_list_or_blob, NULL, NULL};
 static argcheck_T arg24_remote_expr[] = {arg_string, arg_string, arg_string, arg_number};
 static argcheck_T arg23_remove[] = {arg_list_or_dict_or_blob, arg_remove2, arg_number};
@@ -1067,11 +1112,11 @@ static funcentry_T global_functions[] =
                        ret_number_bool,    f_assert_equalfile},
     {"assert_exception", 1, 2, 0,          arg2_string,
                        ret_number_bool,    f_assert_exception},
-    {"assert_fails",   1, 5, FEARG_1,      NULL,
+    {"assert_fails",   1, 5, FEARG_1,      arg15_assert_fails,
                        ret_number_bool,    f_assert_fails},
     {"assert_false",   1, 2, FEARG_1,      NULL,
                        ret_number_bool,    f_assert_false},
-    {"assert_inrange", 3, 4, FEARG_3,      NULL,
+    {"assert_inrange", 3, 4, FEARG_3,      arg34_assert_inrange,
                        ret_number_bool,    f_assert_inrange},
     {"assert_match",   2, 3, FEARG_2,      arg3_string,
                        ret_number_bool,    f_assert_match},
@@ -1325,7 +1370,7 @@ static funcentry_T global_functions[] =
                        ret_f_function,     f_function},
     {"garbagecollect", 0, 1, 0,            arg1_bool,
                        ret_void,           f_garbagecollect},
-    {"get",            2, 3, FEARG_1,      NULL,
+    {"get",            2, 3, FEARG_1,      arg23_get,
                        ret_any,            f_get},
     {"getbufinfo",     0, 1, FEARG_1,      arg1_buffer_or_dict_any,
                        ret_list_dict_any,  f_getbufinfo},
@@ -1515,7 +1560,7 @@ static funcentry_T global_functions[] =
                        ret_list_string,    f_keys},
     {"last_buffer_nr", 0, 0, 0,            NULL,       // obsolete
                        ret_number,         f_last_buffer_nr},
-    {"len",            1, 1, FEARG_1,      NULL,
+    {"len",            1, 1, FEARG_1,      arg1_len,
                        ret_number,         f_len},
     {"libcall",                3, 3, FEARG_3,      arg3_libcall,
                        ret_string,         f_libcall},
@@ -1541,7 +1586,7 @@ static funcentry_T global_functions[] =
                        ret_float,          FLOAT_FUNC(f_log)},
     {"log10",          1, 1, FEARG_1,      arg1_float_or_nr,
                        ret_float,          FLOAT_FUNC(f_log10)},
-    {"luaeval",                1, 2, FEARG_1,      NULL,
+    {"luaeval",                1, 2, FEARG_1,      arg2_string_any,
                        ret_any,
 #ifdef FEAT_LUA
                f_luaeval
@@ -1627,7 +1672,7 @@ static funcentry_T global_functions[] =
                        ret_number,         PROP_FUNC(f_popup_beval)},
     {"popup_clear",    0, 1, 0,            arg1_bool,
                        ret_void,           PROP_FUNC(f_popup_clear)},
-    {"popup_close",    1, 2, FEARG_1,      NULL,
+    {"popup_close",    1, 2, FEARG_1,      arg2_number_any,
                        ret_void,           PROP_FUNC(f_popup_close)},
     {"popup_create",   2, 2, FEARG_1,      arg2_str_or_nr_or_list_dict,
                        ret_number,         PROP_FUNC(f_popup_create)},
@@ -1667,7 +1712,7 @@ static funcentry_T global_functions[] =
                        ret_float,          FLOAT_FUNC(f_pow)},
     {"prevnonblank",   1, 1, FEARG_1,      arg1_lnum,
                        ret_number,         f_prevnonblank},
-    {"printf",         1, 19, FEARG_2,     NULL,
+    {"printf",         1, 19, FEARG_2,     arg119_printf,
                        ret_string,         f_printf},
     {"prompt_getprompt", 1, 1, FEARG_1,            arg1_buffer,
                        ret_string,         JOB_FUNC(f_prompt_getprompt)},
@@ -1829,7 +1874,7 @@ static funcentry_T global_functions[] =
                        ret_bool,           f_setdigraph},
     {"setdigraphlist", 1, 1, FEARG_1,      arg1_list_string,
                        ret_bool,           f_setdigraphlist},
-    {"setenv",         2, 2, FEARG_2,      NULL,
+    {"setenv",         2, 2, FEARG_2,      arg2_string_any,
                        ret_void,           f_setenv},
     {"setfperm",       2, 2, FEARG_1,      arg2_string,
                        ret_number_bool,    f_setfperm},
@@ -1843,7 +1888,7 @@ static funcentry_T global_functions[] =
                        ret_number_bool,    f_setpos},
     {"setqflist",      1, 3, FEARG_1,      arg13_setqflist,
                        ret_number_bool,    f_setqflist},
-    {"setreg",         2, 3, FEARG_2,      NULL,
+    {"setreg",         2, 3, FEARG_2,      arg3_string_any_string,
                        ret_number_bool,    f_setreg},
     {"settabvar",      3, 3, FEARG_3,      arg3_number_string_any,
                        ret_void,           f_settabvar},
@@ -6563,6 +6608,9 @@ f_luaeval(typval_T *argvars, typval_T *rettv)
     if (check_restricted() || check_secure())
        return;
 
+    if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
+       return;
+
     str = tv_get_string_buf(&argvars[0], buf);
     do_luaeval(str, argvars + 1, rettv);
 }
@@ -7139,6 +7187,9 @@ f_printf(typval_T *argvars, typval_T *rettv)
     rettv->v_type = VAR_STRING;
     rettv->vval.v_string = NULL;
 
+    if (in_vim9script() && check_for_string_or_number_arg(argvars, 0) == FAIL)
+       return;
+
     // Get the required length, allocate the buffer and do it for real.
     did_emsg = FALSE;
     fmt = (char *)tv_get_string_buf(&argvars[0], buf);
@@ -8515,8 +8566,12 @@ f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
 {
     char_u   namebuf[NUMBUFLEN];
     char_u   valbuf[NUMBUFLEN];
-    char_u  *name = tv_get_string_buf(&argvars[0], namebuf);
+    char_u  *name;
+
+    if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
+       return;
 
+    name = tv_get_string_buf(&argvars[0], namebuf);
     if (argvars[1].v_type == VAR_SPECIAL
                                      && argvars[1].vval.v_number == VVAL_NULL)
        vim_unsetenv(name);
@@ -8616,6 +8671,11 @@ f_setreg(typval_T *argvars, typval_T *rettv)
     typval_T   *regcontents;
     int                pointreg;
 
+    if (in_vim9script()
+           && (check_for_string_arg(argvars, 0) == FAIL
+               || check_for_opt_string_arg(argvars, 2) == FAIL))
+       return;
+
     pointreg = 0;
     regcontents = NULL;
     block_len = -1;
index f433b875a9874c8cc1040cfcd5fdbf29af57e3a8..97c8fe5c23717ea7e95ccb7e88466cbce048c893 100644 (file)
@@ -2516,9 +2516,13 @@ find_popup_win(int id)
     void
 f_popup_close(typval_T *argvars, typval_T *rettv UNUSED)
 {
-    int                id = (int)tv_get_number(argvars);
+    int                id;
     win_T      *wp;
 
+    if (in_vim9script() && check_for_number_arg(argvars, 0) == FAIL)
+       return;
+
+    id = (int)tv_get_number(argvars);
     if (
 # ifdef FEAT_TERMINAL
        // if the popup contains a terminal it will become hidden
index 8f6e3e16fa3db2cd00cc07078f007946edb4cd10..b6248afc8c7d2828923ec6f41a65c2218bd72c2e 100644 (file)
@@ -14,6 +14,7 @@ int check_for_nonempty_string_arg(typval_T *args, int idx);
 int check_for_opt_string_arg(typval_T *args, int idx);
 int check_for_number_arg(typval_T *args, int idx);
 int check_for_opt_number_arg(typval_T *args, int idx);
+int check_for_float_or_nr_arg(typval_T *args, int idx);
 int check_for_bool_arg(typval_T *args, int idx);
 int check_for_opt_bool_arg(typval_T *args, int idx);
 int check_for_list_arg(typval_T *args, int idx);
@@ -31,6 +32,7 @@ int check_for_opt_lnum_arg(typval_T *args, int idx);
 int check_for_opt_string_or_number_arg(typval_T *args, int idx);
 int check_for_string_or_blob_arg(typval_T *args, int idx);
 int check_for_string_or_list_arg(typval_T *args, int idx);
+int check_for_opt_string_or_list_arg(typval_T *args, int idx);
 int check_for_list_or_blob_arg(typval_T *args, int idx);
 int check_for_list_or_dict_or_blob_arg(typval_T *args, int idx);
 int check_for_buffer_or_dict_arg(typval_T *args, int idx);
index e0dc99e7c6a51c1d6f97ee95048a9fd8ba6409bf..51a0a3e66bfb7fe9802c3f8c7530a5c7b8b1b3a0 100644 (file)
@@ -268,21 +268,21 @@ func Test_assert_fail_fails()
   catch
     let exp = v:exception
   endtry
-  call assert_match("E856: \"assert_fails()\" second argument", exp)
+  call assert_match("E1174: String required for argument 2", exp)
 
   try
     call assert_equal(1, assert_fails('xxx', 'E492', '', 'burp'))
   catch
     let exp = v:exception
   endtry
-  call assert_match("E1115: \"assert_fails()\" fourth argument must be a number", exp)
+  call assert_match("E1210: Number required for argument 4", exp)
 
   try
     call assert_equal(1, assert_fails('xxx', 'E492', '', 54, 123))
   catch
     let exp = v:exception
   endtry
-  call assert_match("E1116: \"assert_fails()\" fifth argument must be a string", exp)
+  call assert_match("E1174: String required for argument 5", exp)
 endfunc
 
 func Test_assert_fails_in_try_block()
index e1316a0656a72be9aa409b35b483a4b14d9af950..4ca4737ecb9d367c3f335c61c9e66080b117f14c 100644 (file)
@@ -234,6 +234,20 @@ def Test_assert_exception()
   CheckDefFailure(['assert_exception("E1:", v:null)'], 'E1013: Argument 2: type mismatch, expected string but got special')
 enddef
 
+def Test_assert_fails()
+  CheckDefAndScriptFailure2(['assert_fails([])'], 'E1013: Argument 1: type mismatch, expected string but got list<unknown>', 'E1174: String required for argument 1')
+  CheckDefAndScriptFailure2(['assert_fails("a", true)'], 'E1013: Argument 2: type mismatch, expected string but got bool', 'E1174: String required for argument 2')
+  CheckDefAndScriptFailure2(['assert_fails("a", "b", "c", "d")'], 'E1013: Argument 4: type mismatch, expected number but got string', 'E1210: Number required for argument 4')
+  CheckDefAndScriptFailure2(['assert_fails("a", "b", "c", 4, 5)'], 'E1013: Argument 5: type mismatch, expected string but got number', 'E1174: String required for argument 5')
+enddef
+
+def Test_assert_inrange()
+  CheckDefAndScriptFailure2(['assert_inrange("a", 2, 3)'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1210: Number required for argument 1')
+  CheckDefAndScriptFailure2(['assert_inrange(1, "b", 3)'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2')
+  CheckDefAndScriptFailure2(['assert_inrange(1, 2, "c")'], 'E1013: Argument 3: type mismatch, expected number but got string', 'E1210: Number required for argument 3')
+  CheckDefAndScriptFailure2(['assert_inrange(1, 2, 3, 4)'], 'E1013: Argument 4: type mismatch, expected string but got number', 'E1174: String required for argument 4')
+enddef
+
 def Test_assert_match()
   CheckDefFailure(['assert_match({}, "b")'], 'E1013: Argument 1: type mismatch, expected string but got dict<unknown>')
   CheckDefFailure(['assert_match("a", 1)'], 'E1013: Argument 2: type mismatch, expected string but got number')
@@ -1144,6 +1158,20 @@ def Test_garbagecollect()
   CheckDefAndScriptFailure2(['garbagecollect(20)'], 'E1013: Argument 1: type mismatch, expected bool but got number', 'E1023: Using a Number as a Bool')
 enddef
 
+def Test_get()
+  CheckDefAndScriptFailure2(['get("a", 1)'], 'E1013: Argument 1: type mismatch, expected list<any> but got string', 'E896: Argument of get() must be a List, Dictionary or Blob')
+  [3, 5, 2]->get(1)->assert_equal(5)
+  [3, 5, 2]->get(3)->assert_equal(0)
+  [3, 5, 2]->get(3, 9)->assert_equal(9)
+  assert_equal(get(0z102030, 2), 0x30)
+  {a: 7, b: 11, c: 13}->get('c')->assert_equal(13)
+  {10: 'a', 20: 'b', 30: 'd'}->get(20)->assert_equal('b')
+  function('max')->get('name')->assert_equal('max')
+  var F: func = function('min', [[5, 8, 6]])
+  F->get('name')->assert_equal('min')
+  F->get('args')->assert_equal([[5, 8, 6]])
+enddef
+
 def Test_getbufinfo()
   var bufinfo = getbufinfo(bufnr())
   getbufinfo('%')->assert_equal(bufinfo)
@@ -1703,6 +1731,15 @@ def Test_keys_return_type()
   var->assert_equal(['a', 'b'])
 enddef
 
+def Test_len()
+  CheckDefAndScriptFailure2(['len(true)'], 'E1013: Argument 1: type mismatch, expected list<any> but got bool', 'E701: Invalid type for len()')
+  assert_equal(2, "ab"->len())
+  assert_equal(3, 456->len())
+  assert_equal(0, []->len())
+  assert_equal(1, {a: 10}->len())
+  assert_equal(4, 0z20304050->len())
+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')
@@ -1764,6 +1801,13 @@ def Test_listener_remove()
   CheckDefAndScriptFailure2(['listener_remove("x")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number')
 enddef
 
+def Test_lua()
+  if !has('lua')
+    CheckFeature lua
+  endif
+  CheckDefAndScriptFailure2(['luaeval(10)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1')
+enddef
+
 def Test_map()
   CheckDefAndScriptFailure2(['map("x", "1")'], 'E1013: Argument 1: type mismatch, expected list<any> but got string', 'E1211: List required for argument 1')
   CheckDefAndScriptFailure2(['map(1, "1")'], 'E1013: Argument 1: type mismatch, expected list<any> but got number', 'E1211: List required for argument 1')
@@ -2112,6 +2156,10 @@ def Test_popup_clear()
   CheckDefAndScriptFailure2(['popup_clear(2)'], 'E1013: Argument 1: type mismatch, expected bool but got number', 'E1023: Using a Number as a Bool')
 enddef
 
+def Test_popup_close()
+  CheckDefAndScriptFailure2(['popup_close("a")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1210: Number required for argument 1')
+enddef
+
 def Test_popup_create()
   # Pass variable of type 'any' to popup_create()
   var what: any = 'Hello'
@@ -2190,6 +2238,12 @@ def Test_prevnonblank()
   assert_equal(0, prevnonblank(1))
 enddef
 
+def Test_printf()
+  CheckDefAndScriptFailure2(['printf([1])'], 'E1013: Argument 1: type mismatch, expected string but got list<number>', 'E1174: String required for argument 1')
+  printf(0x10)->assert_equal('16')
+  assert_equal(" abc", "abc"->printf("%4s"))
+enddef
+
 def Test_prompt_getprompt()
   if !has('channel')
     CheckFeature channel
@@ -2798,6 +2852,10 @@ def Test_setcursorcharpos()
   CheckDefAndScriptFailure2(['setcursorcharpos(1, 2, "3")'], 'E1013: Argument 3: type mismatch, expected number but got string', 'E1210: Number required for argument 3')
 enddef
 
+def Test_setenv()
+  CheckDefAndScriptFailure2(['setenv(1, 2)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1')
+enddef
+
 def Test_setfperm()
   CheckDefFailure(['setfperm(1, "b")'], 'E1013: Argument 1: type mismatch, expected string but got number')
   CheckDefFailure(['setfperm("a", 0z10)'], 'E1013: Argument 2: type mismatch, expected string but got blob')
@@ -2851,6 +2909,8 @@ def Test_setreg()
   setreg('a', reginfo)
   getreginfo('a')->assert_equal(reginfo)
   assert_fails('setreg("ab", 0)', 'E1162:')
+  CheckDefAndScriptFailure2(['setreg(1, "b")'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1')
+  CheckDefAndScriptFailure2(['setreg("a", "b", 3)'], 'E1013: Argument 3: type mismatch, expected string but got number', 'E1174: String required for argument 3')
 enddef 
 
 def Test_settabvar()
index 14684c0961feba69f86b9edb27f814034235f909..c0ab29ea28dd3aae3dfb8c376cb1e72cdb297aa2 100644 (file)
@@ -521,8 +521,8 @@ def Test_try_catch_throw()
   assert_equal(344, n)
 
   try
-    echo len(v:true)
-  catch /E701:/
+    echo range(1, 2, 0)
+  catch /E726:/
     n = 355
   endtry
   assert_equal(355, n)
index 9f3c29422fd940a2989c115063e7feed3b895062..1da1c1cab457f4840d85ec546a9cddc3ce6fad28 100644 (file)
@@ -566,12 +566,23 @@ f_assert_exception(typval_T *argvars, typval_T *rettv)
     void
 f_assert_fails(typval_T *argvars, typval_T *rettv)
 {
-    char_u     *cmd = tv_get_string_chk(&argvars[0]);
+    char_u     *cmd;
     garray_T   ga;
     int                save_trylevel = trylevel;
     int                called_emsg_before = called_emsg;
     char       *wrong_arg_msg = NULL;
 
+    if (check_for_string_or_number_arg(argvars, 0) == FAIL
+           || check_for_opt_string_or_list_arg(argvars, 1) == FAIL
+           || (argvars[1].v_type != VAR_UNKNOWN
+               && (argvars[2].v_type != VAR_UNKNOWN
+                   && (check_for_opt_number_arg(argvars, 3) == FAIL
+                       || (argvars[3].v_type != VAR_UNKNOWN
+                           && check_for_opt_string_arg(argvars, 4) == FAIL)))))
+       return;
+
+    cmd = tv_get_string_chk(&argvars[0]);
+
     // trylevel must be zero for a ":throw" command to be considered failed
     trylevel = 0;
     suppress_errthrow = TRUE;
@@ -799,6 +810,12 @@ assert_inrange(typval_T *argvars)
     void
 f_assert_inrange(typval_T *argvars, typval_T *rettv)
 {
+    if (check_for_float_or_nr_arg(argvars, 0) == FAIL
+           || check_for_float_or_nr_arg(argvars, 1) == FAIL
+           || check_for_float_or_nr_arg(argvars, 2) == FAIL
+           || check_for_opt_string_arg(argvars, 3) == FAIL)
+       return;
+
     rettv->vval.v_number = assert_inrange(argvars);
 }
 
index 61f8eb55b77cf03796104062bb02eaeb2d637ab2..abda5f050438f896dc885ad5d4c6aaf90afab003 100644 (file)
@@ -421,6 +421,23 @@ check_for_opt_number_arg(typval_T *args, int idx)
            || check_for_number_arg(args, idx) != FAIL);
 }
 
+/*
+ * Give an error and return FAIL unless "args[idx]" is a float or a number.
+ */
+    int
+check_for_float_or_nr_arg(typval_T *args, int idx)
+{
+    if (args[idx].v_type != VAR_FLOAT && args[idx].v_type != VAR_NUMBER)
+    {
+       if (idx >= 0)
+           semsg(_(e_number_required_for_argument_nr), idx + 1);
+       else
+           emsg(_(e_numberreq));
+       return FAIL;
+    }
+    return OK;
+}
+
 /*
  * Give an error and return FAIL unless "args[idx]" is a bool.
  */
@@ -652,6 +669,16 @@ check_for_string_or_list_arg(typval_T *args, int idx)
     return OK;
 }
 
+/*
+ * Check for an optional string or list argument at 'idx'
+ */
+    int
+check_for_opt_string_or_list_arg(typval_T *args, int idx)
+{
+    return (args[idx].v_type == VAR_UNKNOWN
+           || check_for_string_or_list_arg(args, idx));
+}
+
 /*
  * Give an error and return FAIL unless "args[idx]" is a list or a blob.
  */
index af7a7fe8678e3e944c9d6b57f86939f4d926bdf7..7d66d8b5b6d4cd897a231ce140b27b355697c0e6 100644 (file)
@@ -755,6 +755,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    3221,
 /**/
     3220,
 /**/