0
0
mirror of https://github.com/vim/vim.git synced 2025-09-28 04:24:06 -04:00

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

Problem:    Vim9: argument types are not checked at compile time.
Solution:   Add several more type checks. (Yegappan Lakshmanan, closes #8632)
This commit is contained in:
Yegappan Lakshmanan
2021-07-25 15:57:32 +02:00
committed by Bram Moolenaar
parent 2ec28aec9d
commit a764e73d4f
9 changed files with 189 additions and 17 deletions

View File

@@ -557,6 +557,44 @@ arg_extend3(type_T *type, argcontext_T *context)
return OK; 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 * Check "type" which is the second argument of remove() (number or string or
* any) * 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[] = {arg_lnum, arg_lnum};
static argcheck_T arg2_lnum_number[] = {arg_lnum, arg_number}; static argcheck_T arg2_lnum_number[] = {arg_lnum, arg_number};
static argcheck_T arg2_number[] = {arg_number, 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_bool[] = {arg_number, arg_bool};
static argcheck_T arg2_number_dict_any[] = {arg_number, arg_dict_any}; static argcheck_T arg2_number_dict_any[] = {arg_number, arg_dict_any};
static argcheck_T arg2_number_list[] = {arg_number, arg_list_any}; static argcheck_T arg2_number_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_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[] = {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_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_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_bool_dict[] = {arg_string, arg_bool, arg_dict_any};
static argcheck_T arg3_string_number_bool[] = {arg_string, arg_number, arg_bool}; 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 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}; static argcheck_T arg5_number[] = {arg_number, arg_number, arg_number, arg_number, arg_number};
/* Function specific argument types (not covered by the above) */ /* 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 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_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}; 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 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_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_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 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 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 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 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 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 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 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_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 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 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 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}; 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}, ret_number_bool, f_assert_equalfile},
{"assert_exception", 1, 2, 0, arg2_string, {"assert_exception", 1, 2, 0, arg2_string,
ret_number_bool, f_assert_exception}, 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}, ret_number_bool, f_assert_fails},
{"assert_false", 1, 2, FEARG_1, NULL, {"assert_false", 1, 2, FEARG_1, NULL,
ret_number_bool, f_assert_false}, 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}, ret_number_bool, f_assert_inrange},
{"assert_match", 2, 3, FEARG_2, arg3_string, {"assert_match", 2, 3, FEARG_2, arg3_string,
ret_number_bool, f_assert_match}, ret_number_bool, f_assert_match},
@@ -1325,7 +1370,7 @@ static funcentry_T global_functions[] =
ret_f_function, f_function}, ret_f_function, f_function},
{"garbagecollect", 0, 1, 0, arg1_bool, {"garbagecollect", 0, 1, 0, arg1_bool,
ret_void, f_garbagecollect}, ret_void, f_garbagecollect},
{"get", 2, 3, FEARG_1, NULL, {"get", 2, 3, FEARG_1, arg23_get,
ret_any, f_get}, ret_any, f_get},
{"getbufinfo", 0, 1, FEARG_1, arg1_buffer_or_dict_any, {"getbufinfo", 0, 1, FEARG_1, arg1_buffer_or_dict_any,
ret_list_dict_any, f_getbufinfo}, ret_list_dict_any, f_getbufinfo},
@@ -1515,7 +1560,7 @@ static funcentry_T global_functions[] =
ret_list_string, f_keys}, ret_list_string, f_keys},
{"last_buffer_nr", 0, 0, 0, NULL, // obsolete {"last_buffer_nr", 0, 0, 0, NULL, // obsolete
ret_number, f_last_buffer_nr}, ret_number, f_last_buffer_nr},
{"len", 1, 1, FEARG_1, NULL, {"len", 1, 1, FEARG_1, arg1_len,
ret_number, f_len}, ret_number, f_len},
{"libcall", 3, 3, FEARG_3, arg3_libcall, {"libcall", 3, 3, FEARG_3, arg3_libcall,
ret_string, f_libcall}, ret_string, f_libcall},
@@ -1541,7 +1586,7 @@ static funcentry_T global_functions[] =
ret_float, FLOAT_FUNC(f_log)}, ret_float, FLOAT_FUNC(f_log)},
{"log10", 1, 1, FEARG_1, arg1_float_or_nr, {"log10", 1, 1, FEARG_1, arg1_float_or_nr,
ret_float, FLOAT_FUNC(f_log10)}, ret_float, FLOAT_FUNC(f_log10)},
{"luaeval", 1, 2, FEARG_1, NULL, {"luaeval", 1, 2, FEARG_1, arg2_string_any,
ret_any, ret_any,
#ifdef FEAT_LUA #ifdef FEAT_LUA
f_luaeval f_luaeval
@@ -1627,7 +1672,7 @@ static funcentry_T global_functions[] =
ret_number, PROP_FUNC(f_popup_beval)}, ret_number, PROP_FUNC(f_popup_beval)},
{"popup_clear", 0, 1, 0, arg1_bool, {"popup_clear", 0, 1, 0, arg1_bool,
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, arg2_number_any,
ret_void, PROP_FUNC(f_popup_close)}, ret_void, PROP_FUNC(f_popup_close)},
{"popup_create", 2, 2, FEARG_1, arg2_str_or_nr_or_list_dict, {"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)},
@@ -1667,7 +1712,7 @@ static funcentry_T global_functions[] =
ret_float, FLOAT_FUNC(f_pow)}, ret_float, FLOAT_FUNC(f_pow)},
{"prevnonblank", 1, 1, FEARG_1, arg1_lnum, {"prevnonblank", 1, 1, FEARG_1, arg1_lnum,
ret_number, f_prevnonblank}, ret_number, f_prevnonblank},
{"printf", 1, 19, FEARG_2, NULL, {"printf", 1, 19, FEARG_2, arg119_printf,
ret_string, f_printf}, ret_string, f_printf},
{"prompt_getprompt", 1, 1, FEARG_1, arg1_buffer, {"prompt_getprompt", 1, 1, FEARG_1, arg1_buffer,
ret_string, JOB_FUNC(f_prompt_getprompt)}, ret_string, JOB_FUNC(f_prompt_getprompt)},
@@ -1829,7 +1874,7 @@ static funcentry_T global_functions[] =
ret_bool, f_setdigraph}, ret_bool, f_setdigraph},
{"setdigraphlist", 1, 1, FEARG_1, arg1_list_string, {"setdigraphlist", 1, 1, FEARG_1, arg1_list_string,
ret_bool, f_setdigraphlist}, ret_bool, f_setdigraphlist},
{"setenv", 2, 2, FEARG_2, NULL, {"setenv", 2, 2, FEARG_2, arg2_string_any,
ret_void, f_setenv}, ret_void, f_setenv},
{"setfperm", 2, 2, FEARG_1, arg2_string, {"setfperm", 2, 2, FEARG_1, arg2_string,
ret_number_bool, f_setfperm}, ret_number_bool, f_setfperm},
@@ -1843,7 +1888,7 @@ static funcentry_T global_functions[] =
ret_number_bool, f_setpos}, ret_number_bool, f_setpos},
{"setqflist", 1, 3, FEARG_1, arg13_setqflist, {"setqflist", 1, 3, FEARG_1, arg13_setqflist,
ret_number_bool, f_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}, ret_number_bool, f_setreg},
{"settabvar", 3, 3, FEARG_3, arg3_number_string_any, {"settabvar", 3, 3, FEARG_3, arg3_number_string_any,
ret_void, f_settabvar}, ret_void, f_settabvar},
@@ -6563,6 +6608,9 @@ f_luaeval(typval_T *argvars, typval_T *rettv)
if (check_restricted() || check_secure()) if (check_restricted() || check_secure())
return; return;
if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
return;
str = tv_get_string_buf(&argvars[0], buf); str = tv_get_string_buf(&argvars[0], buf);
do_luaeval(str, argvars + 1, rettv); do_luaeval(str, argvars + 1, rettv);
} }
@@ -7139,6 +7187,9 @@ f_printf(typval_T *argvars, typval_T *rettv)
rettv->v_type = VAR_STRING; rettv->v_type = VAR_STRING;
rettv->vval.v_string = NULL; 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. // Get the required length, allocate the buffer and do it for real.
did_emsg = FALSE; did_emsg = FALSE;
fmt = (char *)tv_get_string_buf(&argvars[0], buf); 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 namebuf[NUMBUFLEN];
char_u valbuf[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 if (argvars[1].v_type == VAR_SPECIAL
&& argvars[1].vval.v_number == VVAL_NULL) && argvars[1].vval.v_number == VVAL_NULL)
vim_unsetenv(name); vim_unsetenv(name);
@@ -8616,6 +8671,11 @@ f_setreg(typval_T *argvars, typval_T *rettv)
typval_T *regcontents; typval_T *regcontents;
int pointreg; int pointreg;
if (in_vim9script()
&& (check_for_string_arg(argvars, 0) == FAIL
|| check_for_opt_string_arg(argvars, 2) == FAIL))
return;
pointreg = 0; pointreg = 0;
regcontents = NULL; regcontents = NULL;
block_len = -1; block_len = -1;

View File

@@ -2516,9 +2516,13 @@ find_popup_win(int id)
void void
f_popup_close(typval_T *argvars, typval_T *rettv UNUSED) f_popup_close(typval_T *argvars, typval_T *rettv UNUSED)
{ {
int id = (int)tv_get_number(argvars); int id;
win_T *wp; win_T *wp;
if (in_vim9script() && check_for_number_arg(argvars, 0) == FAIL)
return;
id = (int)tv_get_number(argvars);
if ( if (
# ifdef FEAT_TERMINAL # ifdef FEAT_TERMINAL
// if the popup contains a terminal it will become hidden // if the popup contains a terminal it will become hidden

View 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_opt_string_arg(typval_T *args, int idx);
int check_for_number_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_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_bool_arg(typval_T *args, int idx);
int check_for_opt_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); 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_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_blob_arg(typval_T *args, int idx);
int check_for_string_or_list_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_blob_arg(typval_T *args, int idx);
int check_for_list_or_dict_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); int check_for_buffer_or_dict_arg(typval_T *args, int idx);

View File

@@ -268,21 +268,21 @@ func Test_assert_fail_fails()
catch catch
let exp = v:exception let exp = v:exception
endtry endtry
call assert_match("E856: \"assert_fails()\" second argument", exp) call assert_match("E1174: String required for argument 2", exp)
try try
call assert_equal(1, assert_fails('xxx', 'E492', '', 'burp')) call assert_equal(1, assert_fails('xxx', 'E492', '', 'burp'))
catch catch
let exp = v:exception let exp = v:exception
endtry 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 try
call assert_equal(1, assert_fails('xxx', 'E492', '', 54, 123)) call assert_equal(1, assert_fails('xxx', 'E492', '', 54, 123))
catch catch
let exp = v:exception let exp = v:exception
endtry 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 endfunc
func Test_assert_fails_in_try_block() func Test_assert_fails_in_try_block()

View 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') CheckDefFailure(['assert_exception("E1:", v:null)'], 'E1013: Argument 2: type mismatch, expected string but got special')
enddef 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() def Test_assert_match()
CheckDefFailure(['assert_match({}, "b")'], 'E1013: Argument 1: type mismatch, expected string but got dict<unknown>') 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') 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') CheckDefAndScriptFailure2(['garbagecollect(20)'], 'E1013: Argument 1: type mismatch, expected bool but got number', 'E1023: Using a Number as a Bool')
enddef 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() def Test_getbufinfo()
var bufinfo = getbufinfo(bufnr()) var bufinfo = getbufinfo(bufnr())
getbufinfo('%')->assert_equal(bufinfo) getbufinfo('%')->assert_equal(bufinfo)
@@ -1703,6 +1731,15 @@ def Test_keys_return_type()
var->assert_equal(['a', 'b']) var->assert_equal(['a', 'b'])
enddef 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() def Test_libcall()
CheckFeature libcall CheckFeature libcall
CheckDefAndScriptFailure2(['libcall(1, "b", 3)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') CheckDefAndScriptFailure2(['libcall(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') CheckDefAndScriptFailure2(['listener_remove("x")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number')
enddef 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() 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("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') 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') CheckDefAndScriptFailure2(['popup_clear(2)'], 'E1013: Argument 1: type mismatch, expected bool but got number', 'E1023: Using a Number as a Bool')
enddef 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() def Test_popup_create()
# Pass variable of type 'any' to popup_create() # Pass variable of type 'any' to popup_create()
var what: any = 'Hello' var what: any = 'Hello'
@@ -2190,6 +2238,12 @@ def Test_prevnonblank()
assert_equal(0, prevnonblank(1)) assert_equal(0, prevnonblank(1))
enddef 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() def Test_prompt_getprompt()
if !has('channel') if !has('channel')
CheckFeature 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') CheckDefAndScriptFailure2(['setcursorcharpos(1, 2, "3")'], 'E1013: Argument 3: type mismatch, expected number but got string', 'E1210: Number required for argument 3')
enddef 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() def Test_setfperm()
CheckDefFailure(['setfperm(1, "b")'], 'E1013: Argument 1: type mismatch, expected string but got number') 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') CheckDefFailure(['setfperm("a", 0z10)'], 'E1013: Argument 2: type mismatch, expected string but got blob')
@@ -2851,6 +2909,8 @@ def Test_setreg()
setreg('a', reginfo) setreg('a', reginfo)
getreginfo('a')->assert_equal(reginfo) getreginfo('a')->assert_equal(reginfo)
assert_fails('setreg("ab", 0)', 'E1162:') 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 enddef
def Test_settabvar() def Test_settabvar()

View File

@@ -521,8 +521,8 @@ def Test_try_catch_throw()
assert_equal(344, n) assert_equal(344, n)
try try
echo len(v:true) echo range(1, 2, 0)
catch /E701:/ catch /E726:/
n = 355 n = 355
endtry endtry
assert_equal(355, n) assert_equal(355, n)

View File

@@ -566,12 +566,23 @@ f_assert_exception(typval_T *argvars, typval_T *rettv)
void void
f_assert_fails(typval_T *argvars, typval_T *rettv) f_assert_fails(typval_T *argvars, typval_T *rettv)
{ {
char_u *cmd = tv_get_string_chk(&argvars[0]); char_u *cmd;
garray_T ga; garray_T ga;
int save_trylevel = trylevel; int save_trylevel = trylevel;
int called_emsg_before = called_emsg; int called_emsg_before = called_emsg;
char *wrong_arg_msg = NULL; 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 must be zero for a ":throw" command to be considered failed
trylevel = 0; trylevel = 0;
suppress_errthrow = TRUE; suppress_errthrow = TRUE;
@@ -799,6 +810,12 @@ assert_inrange(typval_T *argvars)
void void
f_assert_inrange(typval_T *argvars, typval_T *rettv) 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); rettv->vval.v_number = assert_inrange(argvars);
} }

View File

@@ -421,6 +421,23 @@ check_for_opt_number_arg(typval_T *args, int idx)
|| check_for_number_arg(args, idx) != FAIL); || 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. * 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; 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. * Give an error and return FAIL unless "args[idx]" is a list or a blob.
*/ */

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 */
/**/
3221,
/**/ /**/
3220, 3220,
/**/ /**/