]> granicus.if.org Git - vim/commitdiff
patch 8.2.3150: Vim9: argument types are not checked at compile time v8.2.3150
authorYegappan Lakshmanan <yegappan@yahoo.com>
Sun, 11 Jul 2021 17:44:18 +0000 (19:44 +0200)
committerBram Moolenaar <Bram@vim.org>
Sun, 11 Jul 2021 17:44:18 +0000 (19:44 +0200)
Problem:    Vim9: argument types are not checked at compile time.
Solution:   Add more type checks. (Yegappan Lakshmanan, closes #8545)

src/evalfunc.c
src/testdir/test_vim9_builtin.vim
src/testing.c
src/version.c

index 3041a6c3805d4280b473cd2ac2943c58792a12ad..4aa3b6d2afae991597665dc9c8a94aa8bc890be3 100644 (file)
@@ -322,7 +322,7 @@ arg_string_or_nr(type_T *type, argcontext_T *context)
  * Check "type" is a string or a list of strings.
  */
     static int
-arg_string_or_list(type_T *type, argcontext_T *context)
+arg_string_or_list_string(type_T *type, argcontext_T *context)
 {
     if (type->tt_type == VAR_ANY || type->tt_type == VAR_STRING)
        return OK;
@@ -339,6 +339,19 @@ arg_string_or_list(type_T *type, argcontext_T *context)
     return FAIL;
 }
 
+/*
+ * Check "type" is a string or a list of 'any'
+ */
+    static int
+arg_string_or_list_any(type_T *type, argcontext_T *context)
+{
+    if (type->tt_type == VAR_ANY
+           || type->tt_type == VAR_STRING || type->tt_type == VAR_LIST)
+       return OK;
+    arg_type_mismatch(&t_string, type, context->arg_idx + 1);
+    return FAIL;
+}
+
 /*
  * Check "type" is a list or a dict.
  */
@@ -412,6 +425,20 @@ arg_item_of_prev(type_T *type, argcontext_T *context)
     return check_arg_type(expected, type, context);
 }
 
+/*
+ * Check "type" is a string or a number or a list
+ */
+    static int
+arg_str_or_nr_or_list(type_T *type, argcontext_T *context)
+{
+    if (type->tt_type == VAR_STRING
+                    || type->tt_type == VAR_NUMBER
+                    || type->tt_type == VAR_LIST)
+       return OK;
+    arg_type_mismatch(&t_string, type, context->arg_idx + 1);
+    return FAIL;
+}
+
 /*
  * Check "type" which is the third argument of extend().
  */
@@ -438,7 +465,8 @@ argcheck_T arg1_list_nr[] = {arg_list_number};
 argcheck_T arg1_list_string[] = {arg_list_string};
 argcheck_T arg1_float_or_nr[] = {arg_float_or_nr};
 argcheck_T arg1_string_or_nr[] = {arg_string_or_nr};
-argcheck_T arg1_string_or_list[] = {arg_string_or_list};
+argcheck_T arg1_string_or_list_any[] = {arg_string_or_list_any};
+argcheck_T arg1_string_or_list_string[] = {arg_string_or_list_string};
 argcheck_T arg1_list_or_blob[] = {arg_list_or_blob};
 argcheck_T arg1_chan_or_job[] = {arg_chan_or_job};
 argcheck_T arg2_float_or_nr[] = {arg_float_or_nr, arg_float_or_nr};
@@ -449,14 +477,18 @@ argcheck_T arg2_dict_string[] = {arg_dict_any, arg_string};
 argcheck_T arg2_dict_string_or_nr[] = {arg_dict_any, arg_string_or_nr};
 argcheck_T arg2_string_dict[] = {arg_string, arg_dict_any};
 argcheck_T arg2_listblob_item[] = {arg_list_or_blob, arg_item_of_prev};
-argcheck_T arg2_execute[] = {arg_string_or_list, arg_string};
-argcheck_T arg23_win_execute[] = {arg_number, arg_string_or_list, arg_string};
-argcheck_T arg23_extend[] = {arg_list_or_dict, arg_same_as_prev, arg_extend3};
-argcheck_T arg23_extendnew[] = {arg_list_or_dict, arg_same_struct_as_prev, arg_extend3};
+argcheck_T arg2_str_or_nr_or_list_dict[] = {arg_str_or_nr_or_list, arg_dict_any};
+argcheck_T arg2_string_or_list_dict[] = {arg_string_or_list_any, arg_dict_any};
 argcheck_T arg3_string[] = {arg_string, arg_string, arg_string};
 argcheck_T arg3_number[] = {arg_number, arg_number, arg_number};
 argcheck_T arg3_string_nr_bool[] = {arg_string, arg_number, arg_bool};
 argcheck_T arg3_string_string_nr[] = {arg_string, arg_string, arg_number};
+argcheck_T arg2_execute[] = {arg_string_or_list_string, arg_string};
+argcheck_T arg23_win_execute[] = {arg_number, arg_string_or_list_string, arg_string};
+argcheck_T arg2_setline[] = {arg_string_or_nr, arg_string_or_list_any};
+argcheck_T arg3_setbufline[] = {arg_string_or_nr, arg_string_or_nr, arg_string_or_list_any};
+argcheck_T arg23_extend[] = {arg_list_or_dict, arg_same_as_prev, arg_extend3};
+argcheck_T arg23_extendnew[] = {arg_list_or_dict, arg_same_struct_as_prev, arg_extend3};
 argcheck_T arg3_insert[] = {arg_list_or_blob, arg_item_of_prev, arg_number};
 
 /*
@@ -765,7 +797,7 @@ static funcentry_T global_functions[] =
                        ret_number_bool,    f_assert_notequal},
     {"assert_notmatch",        2, 3, FEARG_2,      arg3_string,
                        ret_number_bool,    f_assert_notmatch},
-    {"assert_report",  1, 1, FEARG_1,      NULL,
+    {"assert_report",  1, 1, FEARG_1,      arg1_string,
                        ret_number_bool,    f_assert_report},
     {"assert_true",    1, 2, FEARG_1,      NULL,
                        ret_number_bool,    f_assert_true},
@@ -781,7 +813,7 @@ static funcentry_T global_functions[] =
            NULL
 #endif
                        },
-    {"balloon_show",   1, 1, FEARG_1,      arg1_string_or_list,
+    {"balloon_show",   1, 1, FEARG_1,      arg1_string_or_list_any,
                        ret_void,
 #ifdef FEAT_BEVAL
            f_balloon_show
@@ -877,7 +909,7 @@ static funcentry_T global_functions[] =
                        ret_number,         f_char2nr},
     {"charclass",      1, 1, FEARG_1,      arg1_string,
                        ret_number,         f_charclass},
-    {"charcol",                1, 1, FEARG_1,      arg1_string_or_list,
+    {"charcol",                1, 1, FEARG_1,      arg1_string_or_list_any,
                        ret_number,         f_charcol},
     {"charidx",                2, 3, FEARG_1,      arg3_string_nr_bool,
                        ret_number,         f_charidx},
@@ -887,7 +919,7 @@ static funcentry_T global_functions[] =
                        ret_number,         f_cindent},
     {"clearmatches",   0, 1, FEARG_1,      arg1_number,
                        ret_void,           f_clearmatches},
-    {"col",            1, 1, FEARG_1,      arg1_string_or_list,
+    {"col",            1, 1, FEARG_1,      arg1_string_or_list_any,
                        ret_number,         f_col},
     {"complete",       2, 2, FEARG_2,      NULL,
                        ret_void,           f_complete},
@@ -1301,17 +1333,17 @@ static funcentry_T global_functions[] =
            NULL
 #endif
                        },
-    {"popup_atcursor", 2, 2, FEARG_1,      NULL,
+    {"popup_atcursor", 2, 2, FEARG_1,      arg2_str_or_nr_or_list_dict,
                        ret_number,         PROP_FUNC(f_popup_atcursor)},
-    {"popup_beval",    2, 2, FEARG_1,      NULL,
+    {"popup_beval",    2, 2, FEARG_1,      arg2_str_or_nr_or_list_dict,
                        ret_number,         PROP_FUNC(f_popup_beval)},
     {"popup_clear",    0, 1, 0,            NULL,
                        ret_void,           PROP_FUNC(f_popup_clear)},
     {"popup_close",    1, 2, FEARG_1,      NULL,
                        ret_void,           PROP_FUNC(f_popup_close)},
-    {"popup_create",   2, 2, FEARG_1,      NULL,
+    {"popup_create",   2, 2, FEARG_1,      arg2_str_or_nr_or_list_dict,
                        ret_number,         PROP_FUNC(f_popup_create)},
-    {"popup_dialog",   2, 2, FEARG_1,      NULL,
+    {"popup_dialog",   2, 2, FEARG_1,      arg2_str_or_nr_or_list_dict,
                        ret_number,         PROP_FUNC(f_popup_dialog)},
     {"popup_filter_menu", 2, 2, 0,         NULL,
                        ret_bool,           PROP_FUNC(f_popup_filter_menu)},
@@ -1331,11 +1363,11 @@ static funcentry_T global_functions[] =
                        ret_list_number,    PROP_FUNC(f_popup_list)},
     {"popup_locate",   2, 2, 0,            arg2_number,
                        ret_number,         PROP_FUNC(f_popup_locate)},
-    {"popup_menu",     2, 2, FEARG_1,      NULL,
+    {"popup_menu",     2, 2, FEARG_1,      arg2_str_or_nr_or_list_dict,
                        ret_number,         PROP_FUNC(f_popup_menu)},
     {"popup_move",     2, 2, FEARG_1,      NULL,
                        ret_void,           PROP_FUNC(f_popup_move)},
-    {"popup_notification", 2, 2, FEARG_1,   NULL,
+    {"popup_notification", 2, 2, FEARG_1,   arg2_str_or_nr_or_list_dict,
                        ret_number,         PROP_FUNC(f_popup_notification)},
     {"popup_setoptions", 2, 2, FEARG_1,            NULL,
                        ret_void,           PROP_FUNC(f_popup_setoptions)},
@@ -1541,7 +1573,7 @@ static funcentry_T global_functions[] =
                        ret_string,         f_shellescape},
     {"shiftwidth",     0, 1, FEARG_1,      arg1_number,
                        ret_number,         f_shiftwidth},
-    {"sign_define",    1, 2, FEARG_1,      arg2_string_dict,
+    {"sign_define",    1, 2, FEARG_1,      arg2_string_or_list_dict,
                        ret_any,            SIGN_FUNC(f_sign_define)},
     {"sign_getdefined",        0, 1, FEARG_1,      NULL,
                        ret_list_dict_any,  SIGN_FUNC(f_sign_getdefined)},
@@ -1553,7 +1585,7 @@ static funcentry_T global_functions[] =
                        ret_number,         SIGN_FUNC(f_sign_place)},
     {"sign_placelist", 1, 1, FEARG_1,      NULL,
                        ret_list_number,    SIGN_FUNC(f_sign_placelist)},
-    {"sign_undefine",  0, 1, FEARG_1,      arg1_string_or_list,
+    {"sign_undefine",  0, 1, FEARG_1,      arg1_string_or_list_string,
                        ret_number_bool,    SIGN_FUNC(f_sign_undefine)},
     {"sign_unplace",   1, 2, FEARG_1,      arg2_string_dict,
                        ret_number_bool,    SIGN_FUNC(f_sign_unplace)},
@@ -1827,7 +1859,7 @@ static funcentry_T global_functions[] =
                        ret_list_any,       f_uniq},
     {"values",         1, 1, FEARG_1,      arg1_dict,
                        ret_list_any,       f_values},
-    {"virtcol",                1, 1, FEARG_1,      arg1_string_or_list,
+    {"virtcol",                1, 1, FEARG_1,      arg1_string_or_list_any,
                        ret_number,         f_virtcol},
     {"visualmode",     0, 1, 0,            NULL,
                        ret_string,         f_visualmode},
index a17d92a19a4f086e2c74f1a754e41616dab526a0..2a58747bf63c4ffb531accdd1554fdce0f3238b7 100644 (file)
@@ -213,12 +213,19 @@ def Test_assert_notmatch()
   CheckDefFailure(['assert_notmatch("a", "b", null)'], 'E1013: Argument 3: type mismatch, expected string but got special')
 enddef
 
+def Test_assert_report()
+  CheckDefAndScriptFailure2(['assert_report([1, 2])'], 'E1013: Argument 1: type mismatch, expected string but got list<number>', 'E1174: String required for argument 1')
+enddef
+
 def Test_balloon_show()
   CheckGui
   CheckFeature balloon_eval
 
   assert_fails('balloon_show(10)', 'E1174:')
   assert_fails('balloon_show(true)', 'E1174:')
+
+  CheckDefAndScriptFailure2(['balloon_show(1.2)'], 'E1013: Argument 1: type mismatch, expected string but got float', 'E1174: String required for argument 1')
+  CheckDefAndScriptFailure2(['balloon_show({"a": 10})'], 'E1013: Argument 1: type mismatch, expected string but got dict<number>', 'E1174: String required for argument 1')
 enddef
 
 def Test_balloon_split()
@@ -387,6 +394,13 @@ enddef
 def Test_charcol()
   CheckDefFailure(['charcol(10)'], 'E1013: Argument 1: type mismatch, expected string but got number')
   CheckDefFailure(['charcol({a: 10})'], 'E1013: Argument 1: type mismatch, expected string but got dict<number>')
+  new
+  setline(1, ['abcdefgh'])
+  cursor(1, 4)
+  assert_equal(4, charcol('.'))
+  assert_equal(9, charcol([1, '$']))
+  assert_equal(0, charcol([10, '$']))
+  bw!
 enddef
 
 def Test_charidx()
@@ -412,8 +426,11 @@ enddef
 
 def Test_col()
   new
-  setline(1, 'asdf')
-  col([1, '$'])->assert_equal(5)
+  setline(1, 'abcdefgh')
+  cursor(1, 4)
+  assert_equal(4, col('.'))
+  col([1, '$'])->assert_equal(9)
+  assert_equal(0, col([10, '$']))
 
   assert_fails('col(true)', 'E1174:')
 
@@ -1503,11 +1520,36 @@ def Test_or()
   CheckDefFailure(['or(0x1, "x")'], 'E1013: Argument 2: type mismatch, expected number but got string')
 enddef
 
+def Test_popup_atcursor()
+  CheckDefAndScriptFailure2(['popup_atcursor({"a": 10}, {})'], 'E1013: Argument 1: type mismatch, expected string but got dict<number>', 'E450: buffer number, text or a list required')
+  CheckDefAndScriptFailure2(['popup_atcursor("a", [1, 2])'], 'E1013: Argument 2: type mismatch, expected dict<any> but got list<number>', 'E715: Dictionary required')
+enddef
+
+def Test_popup_beval()
+  CheckDefAndScriptFailure2(['popup_beval({"a": 10}, {})'], 'E1013: Argument 1: type mismatch, expected string but got dict<number>', 'E450: buffer number, text or a list required')
+  CheckDefAndScriptFailure2(['popup_beval("a", [1, 2])'], 'E1013: Argument 2: type mismatch, expected dict<any> but got list<number>', 'E715: Dictionary required')
+enddef
+
+def Test_popup_dialog()
+  CheckDefAndScriptFailure2(['popup_dialog({"a": 10}, {})'], 'E1013: Argument 1: type mismatch, expected string but got dict<number>', 'E450: buffer number, text or a list required')
+  CheckDefAndScriptFailure2(['popup_dialog("a", [1, 2])'], 'E1013: Argument 2: type mismatch, expected dict<any> but got list<number>', 'E715: Dictionary required')
+enddef
+
 def Test_popup_locate()
   CheckDefAndScriptFailure2(['popup_locate("a", 20)'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number')
   CheckDefAndScriptFailure2(['popup_locate(10, "b")'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E1030: Using a String as a Number')
 enddef
 
+def Test_popup_menu()
+  CheckDefAndScriptFailure2(['popup_menu({"a": 10}, {})'], 'E1013: Argument 1: type mismatch, expected string but got dict<number>', 'E450: buffer number, text or a list required')
+  CheckDefAndScriptFailure2(['popup_menu("a", [1, 2])'], 'E1013: Argument 2: type mismatch, expected dict<any> but got list<number>', 'E715: Dictionary required')
+enddef
+
+def Test_popup_notification()
+  CheckDefAndScriptFailure2(['popup_notification({"a": 10}, {})'], 'E1013: Argument 1: type mismatch, expected string but got dict<number>', 'E450: buffer number, text or a list required')
+  CheckDefAndScriptFailure2(['popup_notification("a", [1, 2])'], 'E1013: Argument 2: type mismatch, expected dict<any> but got list<number>', 'E715: Dictionary required')
+enddef
+
 def Test_prevnonblank()
   CheckDefFailure(['prevnonblank(null)'], 'E1013: Argument 1: type mismatch, expected string but got special')
   assert_equal(0, prevnonblank(1))
@@ -1887,6 +1929,17 @@ def Test_setfperm()
   CheckDefFailure(['setfperm("a", 0z10)'], 'E1013: Argument 2: type mismatch, expected string but got blob')
 enddef
 
+def Test_setline()
+  new
+  setline(1, range(1, 4))
+  assert_equal(['1', '2', '3', '4'], getline(1, '$'))
+  setline(1, ['a', 'b', 'c', 'd'])
+  assert_equal(['a', 'b', 'c', 'd'], getline(1, '$'))
+  setline(1, 'one')
+  assert_equal(['one', 'b', 'c', 'd'], getline(1, '$'))
+  bw!
+enddef
+
 def Test_setloclist()
   var items = [{filename: '/tmp/file', lnum: 1, valid: true}]
   var what = {items: items}
@@ -2301,6 +2354,13 @@ enddef
 
 def Test_virtcol()
   CheckDefAndScriptFailure2(['virtcol(1.1)'], 'E1013: Argument 1: type mismatch, expected string but got float', 'E1174: String required for argument 1')
+  new
+  setline(1, ['abcdefgh'])
+  cursor(1, 4)
+  assert_equal(4, virtcol('.'))
+  assert_equal(9, virtcol([1, '$']))
+  assert_equal(0, virtcol([10, '$']))
+  bw!
 enddef
 
 def Test_win_execute()
index c2389bdeebb986a44a0a86fbea795d7e7a8bed1c..80596d44bc7690f9d1ec742e571babd2efa99553 100644 (file)
@@ -824,6 +824,9 @@ f_assert_report(typval_T *argvars, typval_T *rettv)
 {
     garray_T   ga;
 
+    if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
+       return;
+
     prepare_assert_error(&ga);
     ga_concat(&ga, tv_get_string(&argvars[0]));
     assert_error(&ga);
index 1102e94fc48c0e1f29d9150d6d5b2170ea4fa091..0047c7dbc8784664ff40a1fbf037f7f1a3a5716c 100644 (file)
@@ -755,6 +755,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    3150,
 /**/
     3149,
 /**/