0
0
mirror of https://github.com/vim/vim.git synced 2025-07-26 11:04:33 -04:00

patch 8.2.3173: 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 #8581)
This commit is contained in:
Yegappan Lakshmanan 2021-07-17 19:11:07 +02:00 committed by Bram Moolenaar
parent 20c370d9f2
commit a9a7c0c602
11 changed files with 329 additions and 31 deletions

View 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) f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
{ {
#ifdef FEAT_DIFF #ifdef FEAT_DIFF
linenr_T lnum = tv_get_lnum(argvars); linenr_T lnum;
static linenr_T prev_lnum = 0; static linenr_T prev_lnum = 0;
static varnumber_T changedtick = 0; static varnumber_T changedtick = 0;
static int fnum = 0; static int fnum = 0;
@ -3293,6 +3293,14 @@ f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
int filler_lines; int filler_lines;
int col; 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 if (lnum < 0) // ignore type error in {lnum} arg
lnum = 0; lnum = 0;
if (lnum != prev_lnum if (lnum != prev_lnum

View File

@ -502,3 +502,7 @@ EXTERN char e_invalid_value_for_line_number_str[]
INIT(= N_("E1209: Invalid value for a line number: \"%s\"")); INIT(= N_("E1209: Invalid value for a line number: \"%s\""));
EXTERN char e_number_required_for_argument_nr[] EXTERN char e_number_required_for_argument_nr[]
INIT(= N_("E1210: Number required for argument %d")); 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"));

View 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_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_dict[] = {arg_string, arg_dict_any};
static argcheck_T arg2_string_nr[] = {arg_string, arg_number}; 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_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_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_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_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_nr_dict_any[] = {arg_number, arg_dict_any};
//static argcheck_T arg2_string_number[] = {arg_string, arg_number}; //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_nr_bool[] = {arg_string, arg_number, arg_bool};
static argcheck_T arg3_string_string_nr[] = {arg_string, arg_string, arg_number}; 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 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_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 arg3_insert[] = {arg_list_or_blob, arg_item_of_prev, arg_number}; 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. * 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)}, ret_string, JOB_FUNC(f_ch_status)},
{"changenr", 0, 0, 0, NULL, {"changenr", 0, 0, 0, NULL,
ret_number, f_changenr}, ret_number, f_changenr},
{"char2nr", 1, 2, FEARG_1, NULL, {"char2nr", 1, 2, FEARG_1, arg2_string_bool,
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},
@ -987,7 +991,7 @@ static funcentry_T global_functions[] =
ret_number_bool, f_did_filetype}, ret_number_bool, f_did_filetype},
{"diff_filler", 1, 1, FEARG_1, arg1_string_or_nr, {"diff_filler", 1, 1, FEARG_1, arg1_string_or_nr,
ret_number, f_diff_filler}, 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}, ret_number, f_diff_hlID},
{"echoraw", 1, 1, FEARG_1, arg1_string, {"echoraw", 1, 1, FEARG_1, arg1_string,
ret_void, f_echoraw}, ret_void, f_echoraw},
@ -1251,7 +1255,7 @@ static funcentry_T global_functions[] =
ret_string, f_json_encode}, ret_string, f_json_encode},
{"keys", 1, 1, FEARG_1, arg1_dict_any, {"keys", 1, 1, FEARG_1, arg1_dict_any,
ret_list_string, f_keys}, 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}, ret_number, f_last_buffer_nr},
{"len", 1, 1, FEARG_1, NULL, {"len", 1, 1, FEARG_1, NULL,
ret_number, f_len}, ret_number, f_len},
@ -1297,7 +1301,7 @@ static funcentry_T global_functions[] =
ret_first_cont, f_mapnew}, ret_first_cont, f_mapnew},
{"mapset", 3, 3, FEARG_1, NULL, {"mapset", 3, 3, FEARG_1, NULL,
ret_void, f_mapset}, ret_void, f_mapset},
{"match", 2, 4, FEARG_1, NULL, {"match", 2, 4, FEARG_1, arg4_match_func,
ret_any, f_match}, ret_any, f_match},
{"matchadd", 2, 5, FEARG_1, NULL, {"matchadd", 2, 5, FEARG_1, NULL,
ret_number, f_matchadd}, ret_number, f_matchadd},
@ -1307,17 +1311,17 @@ static funcentry_T global_functions[] =
ret_list_string, f_matcharg}, ret_list_string, f_matcharg},
{"matchdelete", 1, 2, FEARG_1, arg2_number, {"matchdelete", 1, 2, FEARG_1, arg2_number,
ret_number_bool, f_matchdelete}, ret_number_bool, f_matchdelete},
{"matchend", 2, 4, FEARG_1, NULL, {"matchend", 2, 4, FEARG_1, arg4_match_func,
ret_number, f_matchend}, ret_number, f_matchend},
{"matchfuzzy", 2, 3, FEARG_1, NULL, {"matchfuzzy", 2, 3, FEARG_1, NULL,
ret_list_string, f_matchfuzzy}, ret_list_string, f_matchfuzzy},
{"matchfuzzypos", 2, 3, FEARG_1, NULL, {"matchfuzzypos", 2, 3, FEARG_1, NULL,
ret_list_any, f_matchfuzzypos}, ret_list_any, f_matchfuzzypos},
{"matchlist", 2, 4, FEARG_1, NULL, {"matchlist", 2, 4, FEARG_1, arg4_match_func,
ret_list_string, f_matchlist}, ret_list_string, f_matchlist},
{"matchstr", 2, 4, FEARG_1, NULL, {"matchstr", 2, 4, FEARG_1, arg4_match_func,
ret_string, f_matchstr}, ret_string, f_matchstr},
{"matchstrpos", 2, 4, FEARG_1, NULL, {"matchstrpos", 2, 4, FEARG_1, arg4_match_func,
ret_list_any, f_matchstrpos}, ret_list_any, f_matchstrpos},
{"max", 1, 1, FEARG_1, arg1_list_or_dict, {"max", 1, 1, FEARG_1, arg1_list_or_dict,
ret_number, f_max}, ret_number, f_max},
@ -1413,7 +1417,7 @@ static funcentry_T global_functions[] =
ret_void, JOB_FUNC(f_prompt_setcallback)}, ret_void, JOB_FUNC(f_prompt_setcallback)},
{"prompt_setinterrupt", 2, 2, FEARG_1, NULL, {"prompt_setinterrupt", 2, 2, FEARG_1, NULL,
ret_void, JOB_FUNC(f_prompt_setinterrupt)}, 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)}, ret_void, JOB_FUNC(f_prompt_setprompt)},
{"prop_add", 3, 3, FEARG_1, NULL, {"prop_add", 3, 3, FEARG_1, NULL,
ret_void, PROP_FUNC(f_prop_add)}, ret_void, PROP_FUNC(f_prop_add)},
@ -1651,7 +1655,7 @@ static funcentry_T global_functions[] =
ret_string, f_state}, ret_string, f_state},
{"str2float", 1, 1, FEARG_1, arg1_string, {"str2float", 1, 1, FEARG_1, arg1_string,
ret_float, FLOAT_FUNC(f_str2float)}, 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}, ret_list_number, f_str2list},
{"str2nr", 1, 3, FEARG_1, arg3_string_nr_bool, {"str2nr", 1, 3, FEARG_1, arg3_string_nr_bool,
ret_number, f_str2nr}, ret_number, f_str2nr},
@ -1659,7 +1663,7 @@ static funcentry_T global_functions[] =
ret_number, f_strcharlen}, ret_number, f_strcharlen},
{"strcharpart", 2, 4, FEARG_1, NULL, {"strcharpart", 2, 4, FEARG_1, NULL,
ret_string, f_strcharpart}, ret_string, f_strcharpart},
{"strchars", 1, 2, FEARG_1, NULL, {"strchars", 1, 2, FEARG_1, arg2_string_bool,
ret_number, f_strchars}, ret_number, f_strchars},
{"strdisplaywidth", 1, 2, FEARG_1, arg2_string_nr, {"strdisplaywidth", 1, 2, FEARG_1, arg2_string_nr,
ret_number, f_strdisplaywidth}, ret_number, f_strdisplaywidth},
@ -1709,9 +1713,9 @@ static funcentry_T global_functions[] =
ret_string, f_synIDattr}, ret_string, f_synIDattr},
{"synIDtrans", 1, 1, FEARG_1, arg1_number, {"synIDtrans", 1, 1, FEARG_1, arg1_number,
ret_number, f_synIDtrans}, ret_number, f_synIDtrans},
{"synconcealed", 2, 2, 0, NULL, {"synconcealed", 2, 2, 0, arg2_string_or_nr_nr,
ret_list_any, f_synconcealed}, ret_list_any, f_synconcealed},
{"synstack", 2, 2, 0, NULL, {"synstack", 2, 2, 0, arg2_string_or_nr_nr,
ret_list_number, f_synstack}, ret_list_number, f_synstack},
{"system", 1, 2, FEARG_1, NULL, {"system", 1, 2, FEARG_1, NULL,
ret_string, f_system}, ret_string, f_system},
@ -1771,7 +1775,7 @@ static funcentry_T global_functions[] =
ret_list_number, TERM_FUNC(f_term_list)}, ret_list_number, TERM_FUNC(f_term_list)},
{"term_scrape", 2, 2, FEARG_1, NULL, {"term_scrape", 2, 2, FEARG_1, NULL,
ret_list_dict_any, TERM_FUNC(f_term_scrape)}, 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)}, ret_void, TERM_FUNC(f_term_sendkeys)},
{"term_setansicolors", 2, 2, FEARG_1, NULL, {"term_setansicolors", 2, 2, FEARG_1, NULL,
ret_void, ret_void,
@ -1781,17 +1785,17 @@ static funcentry_T global_functions[] =
NULL NULL
#endif #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)}, 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)}, 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)}, ret_void, TERM_FUNC(f_term_setrestore)},
{"term_setsize", 3, 3, FEARG_1, NULL, {"term_setsize", 3, 3, FEARG_1, NULL,
ret_void, TERM_FUNC(f_term_setsize)}, ret_void, TERM_FUNC(f_term_setsize)},
{"term_start", 1, 2, FEARG_1, NULL, {"term_start", 1, 2, FEARG_1, NULL,
ret_number, TERM_FUNC(f_term_start)}, 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)}, ret_void, TERM_FUNC(f_term_wait)},
{"terminalprops", 0, 0, 0, NULL, {"terminalprops", 0, 0, 0, NULL,
ret_dict_string, f_terminalprops}, ret_dict_string, f_terminalprops},
@ -2473,8 +2477,12 @@ f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
static void static void
f_char2nr(typval_T *argvars, typval_T *rettv) 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; return;
if (has_mbyte) if (has_mbyte)
{ {
int utf8 = 0; int utf8 = 0;
@ -6304,6 +6312,17 @@ find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
rettv->vval.v_string = NULL; 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 (argvars[0].v_type == VAR_LIST)
{ {
if ((l = argvars[0].vval.v_list) == NULL) 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); 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) #if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
lnum = tv_get_lnum(argvars); // -1 on type error lnum = tv_get_lnum(argvars); // -1 on type error
col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -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); 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 #ifdef FEAT_SYN_HL
lnum = tv_get_lnum(argvars); // -1 on type error lnum = tv_get_lnum(argvars); // -1 on type error
col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error

View 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_readonlysbx[] INIT(= N_("E794: Cannot set variable in the sandbox: \"%s\""));
EXTERN char e_stringreq[] INIT(= N_("E928: String required")); EXTERN char e_stringreq[] INIT(= N_("E928: String required"));
EXTERN char e_numberreq[] INIT(= N_("E889: Number 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_emptykey[] INIT(= N_("E713: Cannot use empty key for Dictionary"));
EXTERN char e_dictreq[] INIT(= N_("E715: Dictionary required")); EXTERN char e_dictreq[] INIT(= N_("E715: Dictionary required"));
EXTERN char e_listidx[] INIT(= N_("E684: list index out of range: %ld")); EXTERN char e_listidx[] INIT(= N_("E684: list index out of range: %ld"));

View File

@ -1725,6 +1725,13 @@ f_prompt_setprompt(typval_T *argvars, typval_T *rettv UNUSED)
buf_T *buf; buf_T *buf;
char_u *text; 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()) if (check_secure())
return; return;
buf = tv_get_buf(&argvars[0], FALSE); buf = tv_get_buf(&argvars[0], FALSE);

View 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_string_arg(typval_T *args, int idx);
int check_for_nonempty_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_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); int check_for_dict_arg(typval_T *args, int idx);
char_u *tv_get_string(typval_T *varp); char_u *tv_get_string(typval_T *varp);
char_u *tv_get_string_strict(typval_T *varp); char_u *tv_get_string_strict(typval_T *varp);

View File

@ -902,6 +902,12 @@ f_str2list(typval_T *argvars, typval_T *rettv)
if (rettv_list_alloc(rettv) == FAIL) if (rettv_list_alloc(rettv) == FAIL)
return; 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) if (argvars[1].v_type != VAR_UNKNOWN)
utf8 = (int)tv_get_bool_chk(&argvars[1], NULL); 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; 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) if (argvars[1].v_type != VAR_UNKNOWN)
skipcc = tv_get_bool(&argvars[1]); skipcc = tv_get_bool(&argvars[1]);
if (skipcc < 0 || skipcc > 1) if (skipcc < 0 || skipcc > 1)

View File

@ -6093,10 +6093,18 @@ f_term_scrape(typval_T *argvars, typval_T *rettv)
void void
f_term_sendkeys(typval_T *argvars, typval_T *rettv UNUSED) 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; char_u *msg;
term_T *term; 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) if (buf == NULL)
return; return;
@ -6193,10 +6201,18 @@ f_term_setansicolors(typval_T *argvars, typval_T *rettv UNUSED)
void void
f_term_setapi(typval_T *argvars, typval_T *rettv UNUSED) 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; term_T *term;
char_u *api; 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) if (buf == NULL)
return; return;
term = buf->b_term; 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) f_term_setrestore(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
{ {
#if defined(FEAT_SESSION) #if defined(FEAT_SESSION)
buf_T *buf = term_get_buf(argvars, "term_setrestore()"); buf_T *buf;
term_T *term; term_T *term;
char_u *cmd; 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) if (buf == NULL)
return; return;
term = buf->b_term; term = buf->b_term;
@ -6237,10 +6261,18 @@ f_term_setrestore(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
void void
f_term_setkill(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 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; term_T *term;
char_u *how; 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) if (buf == NULL)
return; return;
term = buf->b_term; term = buf->b_term;
@ -6286,8 +6318,17 @@ f_term_start(typval_T *argvars, typval_T *rettv)
void void
f_term_wait(typval_T *argvars, typval_T *rettv UNUSED) 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) if (buf == NULL)
return; return;
if (buf->b_term->tl_job == NULL) if (buf->b_term->tl_job == NULL)

View File

@ -473,6 +473,12 @@ def Test_char2nr()
char2nr('あ', true)->assert_equal(12354) char2nr('あ', true)->assert_equal(12354)
assert_fails('char2nr(true)', 'E1174:') 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 enddef
def Test_charclass() def Test_charclass()
@ -602,6 +608,11 @@ def Test_diff_filler()
assert_equal(0, diff_filler('.')) assert_equal(0, diff_filler('.'))
enddef 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() def Test_echoraw()
CheckDefAndScriptFailure2(['echoraw(1)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') 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') 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') delete('Xtmpfile')
enddef 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() def Test_matcharg()
CheckDefFailure(['matcharg("x")'], 'E1013: Argument 1: type mismatch, expected number but got string') CheckDefFailure(['matcharg("x")'], 'E1013: Argument 1: type mismatch, expected number but got string')
enddef enddef
@ -1609,6 +1635,71 @@ def Test_matchdelete()
CheckDefFailure(['matchdelete(1, "x")'], 'E1013: Argument 2: type mismatch, expected number but got string') CheckDefFailure(['matchdelete(1, "x")'], 'E1013: Argument 2: type mismatch, expected number but got string')
enddef 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() def Test_max()
g:flag = true g:flag = true
var l1: list<number> = g:flag var l1: list<number> = g:flag
@ -1792,6 +1883,14 @@ def Test_prompt_getprompt()
endif endif
enddef 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() 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])'], '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') 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 endif
enddef 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() def Test_str2nr()
str2nr("1'000'000", 10, true)->assert_equal(1000000) str2nr("1'000'000", 10, true)->assert_equal(1000000)
@ -2426,6 +2533,11 @@ enddef
def Test_strchars() def Test_strchars()
strchars("A\u20dd", true)->assert_equal(1) 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 enddef
def Test_strdisplaywidth() def Test_strdisplaywidth()
@ -2521,6 +2633,16 @@ def Test_synIDtrans()
CheckDefFailure(['synIDtrans("a")'], 'E1013: Argument 1: type mismatch, expected number but got string') CheckDefFailure(['synIDtrans("a")'], 'E1013: Argument 1: type mismatch, expected number but got string')
enddef 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() def Test_tabpagebuflist()
CheckDefFailure(['tabpagebuflist("t")'], 'E1013: Argument 1: type mismatch, expected number but got string') CheckDefFailure(['tabpagebuflist("t")'], 'E1013: Argument 1: type mismatch, expected number but got string')
assert_equal([bufnr('')], tabpagebuflist()) assert_equal([bufnr('')], tabpagebuflist())
@ -2607,6 +2729,29 @@ def Test_term_gettty()
endif endif
enddef 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() def Test_term_start()
if !has('terminal') if !has('terminal')
MissingFeature 'terminal' MissingFeature 'terminal'
@ -2619,6 +2764,12 @@ def Test_term_start()
endif endif
enddef 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() 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("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') CheckDefAndScriptFailure2(['test_alloc_fail(10, "b", 20)'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E474: Invalid argument')

View File

@ -352,7 +352,7 @@ tv_get_float(typval_T *varp)
#endif #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 int
check_for_string_arg(typval_T *args, int idx) 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 int
check_for_number_arg(typval_T *args, int idx) 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 int
check_for_dict_arg(typval_T *args, int idx) check_for_dict_arg(typval_T *args, int idx)

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 */
/**/
3173,
/**/ /**/
3172, 3172,
/**/ /**/