0
0
mirror of https://github.com/vim/vim.git synced 2025-09-25 03:54:15 -04:00

patch 8.2.3150: Vim9: argument types are not checked at compile time

Problem:    Vim9: argument types are not checked at compile time.
Solution:   Add more type checks. (Yegappan Lakshmanan, closes #8545)
This commit is contained in:
Yegappan Lakshmanan
2021-07-11 19:44:18 +02:00
committed by Bram Moolenaar
parent cc7eb2aa7a
commit c72bdd28ac
4 changed files with 118 additions and 21 deletions

View 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. * Check "type" is a string or a list of strings.
*/ */
static int 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) if (type->tt_type == VAR_ANY || type->tt_type == VAR_STRING)
return OK; return OK;
@@ -339,6 +339,19 @@ arg_string_or_list(type_T *type, argcontext_T *context)
return FAIL; 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. * 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); 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(). * 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_list_string[] = {arg_list_string};
argcheck_T arg1_float_or_nr[] = {arg_float_or_nr}; 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_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_list_or_blob[] = {arg_list_or_blob};
argcheck_T arg1_chan_or_job[] = {arg_chan_or_job}; argcheck_T arg1_chan_or_job[] = {arg_chan_or_job};
argcheck_T arg2_float_or_nr[] = {arg_float_or_nr, arg_float_or_nr}; 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_dict_string_or_nr[] = {arg_dict_any, arg_string_or_nr};
argcheck_T arg2_string_dict[] = {arg_string, arg_dict_any}; 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_listblob_item[] = {arg_list_or_blob, arg_item_of_prev};
argcheck_T arg2_execute[] = {arg_string_or_list, arg_string}; argcheck_T arg2_str_or_nr_or_list_dict[] = {arg_str_or_nr_or_list, arg_dict_any};
argcheck_T arg23_win_execute[] = {arg_number, arg_string_or_list, arg_string}; argcheck_T arg2_string_or_list_dict[] = {arg_string_or_list_any, arg_dict_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_string[] = {arg_string, arg_string, arg_string}; argcheck_T arg3_string[] = {arg_string, arg_string, arg_string};
argcheck_T arg3_number[] = {arg_number, arg_number, arg_number}; 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_nr_bool[] = {arg_string, arg_number, arg_bool};
argcheck_T arg3_string_string_nr[] = {arg_string, arg_string, arg_number}; 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}; 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}, ret_number_bool, f_assert_notequal},
{"assert_notmatch", 2, 3, FEARG_2, arg3_string, {"assert_notmatch", 2, 3, FEARG_2, arg3_string,
ret_number_bool, f_assert_notmatch}, 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}, ret_number_bool, f_assert_report},
{"assert_true", 1, 2, FEARG_1, NULL, {"assert_true", 1, 2, FEARG_1, NULL,
ret_number_bool, f_assert_true}, ret_number_bool, f_assert_true},
@@ -781,7 +813,7 @@ static funcentry_T global_functions[] =
NULL NULL
#endif #endif
}, },
{"balloon_show", 1, 1, FEARG_1, arg1_string_or_list, {"balloon_show", 1, 1, FEARG_1, arg1_string_or_list_any,
ret_void, ret_void,
#ifdef FEAT_BEVAL #ifdef FEAT_BEVAL
f_balloon_show f_balloon_show
@@ -877,7 +909,7 @@ static funcentry_T global_functions[] =
ret_number, f_char2nr}, ret_number, f_char2nr},
{"charclass", 1, 1, FEARG_1, arg1_string, {"charclass", 1, 1, FEARG_1, arg1_string,
ret_number, f_charclass}, 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}, ret_number, f_charcol},
{"charidx", 2, 3, FEARG_1, arg3_string_nr_bool, {"charidx", 2, 3, FEARG_1, arg3_string_nr_bool,
ret_number, f_charidx}, ret_number, f_charidx},
@@ -887,7 +919,7 @@ static funcentry_T global_functions[] =
ret_number, f_cindent}, ret_number, f_cindent},
{"clearmatches", 0, 1, FEARG_1, arg1_number, {"clearmatches", 0, 1, FEARG_1, arg1_number,
ret_void, f_clearmatches}, 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}, ret_number, f_col},
{"complete", 2, 2, FEARG_2, NULL, {"complete", 2, 2, FEARG_2, NULL,
ret_void, f_complete}, ret_void, f_complete},
@@ -1301,17 +1333,17 @@ static funcentry_T global_functions[] =
NULL NULL
#endif #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)}, 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)}, ret_number, PROP_FUNC(f_popup_beval)},
{"popup_clear", 0, 1, 0, NULL, {"popup_clear", 0, 1, 0, NULL,
ret_void, PROP_FUNC(f_popup_clear)}, ret_void, PROP_FUNC(f_popup_clear)},
{"popup_close", 1, 2, FEARG_1, NULL, {"popup_close", 1, 2, FEARG_1, NULL,
ret_void, PROP_FUNC(f_popup_close)}, 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)}, 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)}, ret_number, PROP_FUNC(f_popup_dialog)},
{"popup_filter_menu", 2, 2, 0, NULL, {"popup_filter_menu", 2, 2, 0, NULL,
ret_bool, PROP_FUNC(f_popup_filter_menu)}, 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)}, ret_list_number, PROP_FUNC(f_popup_list)},
{"popup_locate", 2, 2, 0, arg2_number, {"popup_locate", 2, 2, 0, arg2_number,
ret_number, PROP_FUNC(f_popup_locate)}, 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)}, ret_number, PROP_FUNC(f_popup_menu)},
{"popup_move", 2, 2, FEARG_1, NULL, {"popup_move", 2, 2, FEARG_1, NULL,
ret_void, PROP_FUNC(f_popup_move)}, 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)}, ret_number, PROP_FUNC(f_popup_notification)},
{"popup_setoptions", 2, 2, FEARG_1, NULL, {"popup_setoptions", 2, 2, FEARG_1, NULL,
ret_void, PROP_FUNC(f_popup_setoptions)}, ret_void, PROP_FUNC(f_popup_setoptions)},
@@ -1541,7 +1573,7 @@ static funcentry_T global_functions[] =
ret_string, f_shellescape}, ret_string, f_shellescape},
{"shiftwidth", 0, 1, FEARG_1, arg1_number, {"shiftwidth", 0, 1, FEARG_1, arg1_number,
ret_number, f_shiftwidth}, 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)}, ret_any, SIGN_FUNC(f_sign_define)},
{"sign_getdefined", 0, 1, FEARG_1, NULL, {"sign_getdefined", 0, 1, FEARG_1, NULL,
ret_list_dict_any, SIGN_FUNC(f_sign_getdefined)}, 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)}, ret_number, SIGN_FUNC(f_sign_place)},
{"sign_placelist", 1, 1, FEARG_1, NULL, {"sign_placelist", 1, 1, FEARG_1, NULL,
ret_list_number, SIGN_FUNC(f_sign_placelist)}, 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)}, ret_number_bool, SIGN_FUNC(f_sign_undefine)},
{"sign_unplace", 1, 2, FEARG_1, arg2_string_dict, {"sign_unplace", 1, 2, FEARG_1, arg2_string_dict,
ret_number_bool, SIGN_FUNC(f_sign_unplace)}, ret_number_bool, SIGN_FUNC(f_sign_unplace)},
@@ -1827,7 +1859,7 @@ static funcentry_T global_functions[] =
ret_list_any, f_uniq}, ret_list_any, f_uniq},
{"values", 1, 1, FEARG_1, arg1_dict, {"values", 1, 1, FEARG_1, arg1_dict,
ret_list_any, f_values}, 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}, ret_number, f_virtcol},
{"visualmode", 0, 1, 0, NULL, {"visualmode", 0, 1, 0, NULL,
ret_string, f_visualmode}, ret_string, f_visualmode},

View 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') CheckDefFailure(['assert_notmatch("a", "b", null)'], 'E1013: Argument 3: type mismatch, expected string but got special')
enddef 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() def Test_balloon_show()
CheckGui CheckGui
CheckFeature balloon_eval CheckFeature balloon_eval
assert_fails('balloon_show(10)', 'E1174:') assert_fails('balloon_show(10)', 'E1174:')
assert_fails('balloon_show(true)', '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 enddef
def Test_balloon_split() def Test_balloon_split()
@@ -387,6 +394,13 @@ enddef
def Test_charcol() def Test_charcol()
CheckDefFailure(['charcol(10)'], 'E1013: Argument 1: type mismatch, expected string but got number') 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>') 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 enddef
def Test_charidx() def Test_charidx()
@@ -412,8 +426,11 @@ enddef
def Test_col() def Test_col()
new new
setline(1, 'asdf') setline(1, 'abcdefgh')
col([1, '$'])->assert_equal(5) cursor(1, 4)
assert_equal(4, col('.'))
col([1, '$'])->assert_equal(9)
assert_equal(0, col([10, '$']))
assert_fails('col(true)', 'E1174:') 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') CheckDefFailure(['or(0x1, "x")'], 'E1013: Argument 2: type mismatch, expected number but got string')
enddef 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() 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("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') CheckDefAndScriptFailure2(['popup_locate(10, "b")'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E1030: Using a String as a Number')
enddef 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() def Test_prevnonblank()
CheckDefFailure(['prevnonblank(null)'], 'E1013: Argument 1: type mismatch, expected string but got special') CheckDefFailure(['prevnonblank(null)'], 'E1013: Argument 1: type mismatch, expected string but got special')
assert_equal(0, prevnonblank(1)) 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') CheckDefFailure(['setfperm("a", 0z10)'], 'E1013: Argument 2: type mismatch, expected string but got blob')
enddef 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() def Test_setloclist()
var items = [{filename: '/tmp/file', lnum: 1, valid: true}] var items = [{filename: '/tmp/file', lnum: 1, valid: true}]
var what = {items: items} var what = {items: items}
@@ -2301,6 +2354,13 @@ enddef
def Test_virtcol() def Test_virtcol()
CheckDefAndScriptFailure2(['virtcol(1.1)'], 'E1013: Argument 1: type mismatch, expected string but got float', 'E1174: String required for argument 1') 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 enddef
def Test_win_execute() def Test_win_execute()

View File

@@ -824,6 +824,9 @@ f_assert_report(typval_T *argvars, typval_T *rettv)
{ {
garray_T ga; garray_T ga;
if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
return;
prepare_assert_error(&ga); prepare_assert_error(&ga);
ga_concat(&ga, tv_get_string(&argvars[0])); ga_concat(&ga, tv_get_string(&argvars[0]));
assert_error(&ga); assert_error(&ga);

View File

@@ -755,6 +755,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
3150,
/**/ /**/
3149, 3149,
/**/ /**/