Skip to content

Commit a9a7c0c

Browse files
yegappanbrammool
authored andcommitted
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)
1 parent 20c370d commit a9a7c0c

11 files changed

Lines changed: 329 additions & 31 deletions

File tree

src/diff.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3283,7 +3283,7 @@ f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
32833283
f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
32843284
{
32853285
#ifdef FEAT_DIFF
3286-
linenr_T lnum = tv_get_lnum(argvars);
3286+
linenr_T lnum;
32873287
static linenr_T prev_lnum = 0;
32883288
static varnumber_T changedtick = 0;
32893289
static int fnum = 0;
@@ -3293,6 +3293,14 @@ f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
32933293
int filler_lines;
32943294
int col;
32953295

3296+
if (in_vim9script()
3297+
&& ((argvars[0].v_type != VAR_STRING
3298+
&& argvars[0].v_type != VAR_NUMBER
3299+
&& check_for_string_arg(argvars, 0) == FAIL)
3300+
|| check_for_number_arg(argvars, 1) == FAIL))
3301+
return;
3302+
3303+
lnum = tv_get_lnum(argvars);
32963304
if (lnum < 0) // ignore type error in {lnum} arg
32973305
lnum = 0;
32983306
if (lnum != prev_lnum

src/errors.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,3 +502,7 @@ EXTERN char e_invalid_value_for_line_number_str[]
502502
INIT(= N_("E1209: Invalid value for a line number: \"%s\""));
503503
EXTERN char e_number_required_for_argument_nr[]
504504
INIT(= N_("E1210: Number required for argument %d"));
505+
EXTERN char e_list_required_for_argument_nr[]
506+
INIT(= N_("E1211: List required for argument %d"));
507+
EXTERN char e_bool_required_for_argument_nr[]
508+
INIT(= N_("E1211: Bool required for argument %d"));

src/evalfunc.c

Lines changed: 55 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -499,9 +499,12 @@ static argcheck_T arg2_dict_string[] = {arg_dict_any, arg_string};
499499
static argcheck_T arg2_dict_string_or_nr[] = {arg_dict_any, arg_string_or_nr};
500500
static argcheck_T arg2_string_dict[] = {arg_string, arg_dict_any};
501501
static argcheck_T arg2_string_nr[] = {arg_string, arg_number};
502+
static argcheck_T arg2_string_bool[] = {arg_string, arg_bool};
502503
//static argcheck_T arg2_listblob_item[] = {arg_list_or_blob, arg_item_of_prev};
503504
static argcheck_T arg2_str_or_nr_or_list_dict[] = {arg_str_or_nr_or_list, arg_dict_any};
504505
static argcheck_T arg2_string_or_list_dict[] = {arg_string_or_list_any, arg_dict_any};
506+
static argcheck_T arg2_string_or_nr_string[] = {arg_string_or_nr, arg_string};
507+
static argcheck_T arg2_string_or_nr_nr[] = {arg_string_or_nr, arg_number};
505508
static argcheck_T arg2_chan_or_job_dict[] = {arg_chan_or_job, arg_dict_any};
506509
static argcheck_T arg2_nr_dict_any[] = {arg_number, arg_dict_any};
507510
//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};
510513
static argcheck_T arg3_string_nr_bool[] = {arg_string, arg_number, arg_bool};
511514
static argcheck_T arg3_string_string_nr[] = {arg_string, arg_string, arg_number};
512515
static argcheck_T arg2_execute[] = {arg_string_or_list_string, arg_string};
513-
static argcheck_T arg23_win_execute[] = {arg_number, arg_string_or_list_string, arg_string};
514-
static argcheck_T arg2_setline[] = {arg_string_or_nr, NULL};
515-
static argcheck_T arg3_setbufline[] = {arg_string_or_nr, arg_string_or_nr, arg_str_or_nr_or_list};
516516
static argcheck_T arg23_extend[] = {arg_list_or_dict, arg_same_as_prev, arg_extend3};
517517
static argcheck_T arg23_extendnew[] = {arg_list_or_dict, arg_same_struct_as_prev, arg_extend3};
518518
static argcheck_T arg3_insert[] = {arg_list_or_blob, arg_item_of_prev, arg_number};
519+
static argcheck_T arg3_setbufline[] = {arg_string_or_nr, arg_string_or_nr, arg_str_or_nr_or_list};
520+
static argcheck_T arg2_setline[] = {arg_string_or_nr, NULL};
521+
static argcheck_T arg23_win_execute[] = {arg_number, arg_string_or_list_string, arg_string};
522+
static argcheck_T arg4_match_func[] = {arg_string_or_list_any, arg_string, arg_number, arg_number};
519523

520524
/*
521525
* Functions that return the return type of a builtin function.
@@ -931,7 +935,7 @@ static funcentry_T global_functions[] =
931935
ret_string, JOB_FUNC(f_ch_status)},
932936
{"changenr", 0, 0, 0, NULL,
933937
ret_number, f_changenr},
934-
{"char2nr", 1, 2, FEARG_1, NULL,
938+
{"char2nr", 1, 2, FEARG_1, arg2_string_bool,
935939
ret_number, f_char2nr},
936940
{"charclass", 1, 1, FEARG_1, arg1_string,
937941
ret_number, f_charclass},
@@ -987,7 +991,7 @@ static funcentry_T global_functions[] =
987991
ret_number_bool, f_did_filetype},
988992
{"diff_filler", 1, 1, FEARG_1, arg1_string_or_nr,
989993
ret_number, f_diff_filler},
990-
{"diff_hlID", 2, 2, FEARG_1, NULL,
994+
{"diff_hlID", 2, 2, FEARG_1, arg2_string_or_nr_nr,
991995
ret_number, f_diff_hlID},
992996
{"echoraw", 1, 1, FEARG_1, arg1_string,
993997
ret_void, f_echoraw},
@@ -1251,7 +1255,7 @@ static funcentry_T global_functions[] =
12511255
ret_string, f_json_encode},
12521256
{"keys", 1, 1, FEARG_1, arg1_dict_any,
12531257
ret_list_string, f_keys},
1254-
{"last_buffer_nr", 0, 0, 0, arg1_string_or_nr, // obsolete
1258+
{"last_buffer_nr", 0, 0, 0, NULL, // obsolete
12551259
ret_number, f_last_buffer_nr},
12561260
{"len", 1, 1, FEARG_1, NULL,
12571261
ret_number, f_len},
@@ -1297,7 +1301,7 @@ static funcentry_T global_functions[] =
12971301
ret_first_cont, f_mapnew},
12981302
{"mapset", 3, 3, FEARG_1, NULL,
12991303
ret_void, f_mapset},
1300-
{"match", 2, 4, FEARG_1, NULL,
1304+
{"match", 2, 4, FEARG_1, arg4_match_func,
13011305
ret_any, f_match},
13021306
{"matchadd", 2, 5, FEARG_1, NULL,
13031307
ret_number, f_matchadd},
@@ -1307,17 +1311,17 @@ static funcentry_T global_functions[] =
13071311
ret_list_string, f_matcharg},
13081312
{"matchdelete", 1, 2, FEARG_1, arg2_number,
13091313
ret_number_bool, f_matchdelete},
1310-
{"matchend", 2, 4, FEARG_1, NULL,
1314+
{"matchend", 2, 4, FEARG_1, arg4_match_func,
13111315
ret_number, f_matchend},
13121316
{"matchfuzzy", 2, 3, FEARG_1, NULL,
13131317
ret_list_string, f_matchfuzzy},
13141318
{"matchfuzzypos", 2, 3, FEARG_1, NULL,
13151319
ret_list_any, f_matchfuzzypos},
1316-
{"matchlist", 2, 4, FEARG_1, NULL,
1320+
{"matchlist", 2, 4, FEARG_1, arg4_match_func,
13171321
ret_list_string, f_matchlist},
1318-
{"matchstr", 2, 4, FEARG_1, NULL,
1322+
{"matchstr", 2, 4, FEARG_1, arg4_match_func,
13191323
ret_string, f_matchstr},
1320-
{"matchstrpos", 2, 4, FEARG_1, NULL,
1324+
{"matchstrpos", 2, 4, FEARG_1, arg4_match_func,
13211325
ret_list_any, f_matchstrpos},
13221326
{"max", 1, 1, FEARG_1, arg1_list_or_dict,
13231327
ret_number, f_max},
@@ -1413,7 +1417,7 @@ static funcentry_T global_functions[] =
14131417
ret_void, JOB_FUNC(f_prompt_setcallback)},
14141418
{"prompt_setinterrupt", 2, 2, FEARG_1, NULL,
14151419
ret_void, JOB_FUNC(f_prompt_setinterrupt)},
1416-
{"prompt_setprompt", 2, 2, FEARG_1, NULL,
1420+
{"prompt_setprompt", 2, 2, FEARG_1, arg2_string_or_nr_string,
14171421
ret_void, JOB_FUNC(f_prompt_setprompt)},
14181422
{"prop_add", 3, 3, FEARG_1, NULL,
14191423
ret_void, PROP_FUNC(f_prop_add)},
@@ -1651,15 +1655,15 @@ static funcentry_T global_functions[] =
16511655
ret_string, f_state},
16521656
{"str2float", 1, 1, FEARG_1, arg1_string,
16531657
ret_float, FLOAT_FUNC(f_str2float)},
1654-
{"str2list", 1, 2, FEARG_1, NULL,
1658+
{"str2list", 1, 2, FEARG_1, arg2_string_bool,
16551659
ret_list_number, f_str2list},
16561660
{"str2nr", 1, 3, FEARG_1, arg3_string_nr_bool,
16571661
ret_number, f_str2nr},
16581662
{"strcharlen", 1, 1, FEARG_1, arg1_string_or_nr,
16591663
ret_number, f_strcharlen},
16601664
{"strcharpart", 2, 4, FEARG_1, NULL,
16611665
ret_string, f_strcharpart},
1662-
{"strchars", 1, 2, FEARG_1, NULL,
1666+
{"strchars", 1, 2, FEARG_1, arg2_string_bool,
16631667
ret_number, f_strchars},
16641668
{"strdisplaywidth", 1, 2, FEARG_1, arg2_string_nr,
16651669
ret_number, f_strdisplaywidth},
@@ -1709,9 +1713,9 @@ static funcentry_T global_functions[] =
17091713
ret_string, f_synIDattr},
17101714
{"synIDtrans", 1, 1, FEARG_1, arg1_number,
17111715
ret_number, f_synIDtrans},
1712-
{"synconcealed", 2, 2, 0, NULL,
1716+
{"synconcealed", 2, 2, 0, arg2_string_or_nr_nr,
17131717
ret_list_any, f_synconcealed},
1714-
{"synstack", 2, 2, 0, NULL,
1718+
{"synstack", 2, 2, 0, arg2_string_or_nr_nr,
17151719
ret_list_number, f_synstack},
17161720
{"system", 1, 2, FEARG_1, NULL,
17171721
ret_string, f_system},
@@ -1771,7 +1775,7 @@ static funcentry_T global_functions[] =
17711775
ret_list_number, TERM_FUNC(f_term_list)},
17721776
{"term_scrape", 2, 2, FEARG_1, NULL,
17731777
ret_list_dict_any, TERM_FUNC(f_term_scrape)},
1774-
{"term_sendkeys", 2, 2, FEARG_1, NULL,
1778+
{"term_sendkeys", 2, 2, FEARG_1, arg2_string_or_nr_string,
17751779
ret_void, TERM_FUNC(f_term_sendkeys)},
17761780
{"term_setansicolors", 2, 2, FEARG_1, NULL,
17771781
ret_void,
@@ -1781,17 +1785,17 @@ static funcentry_T global_functions[] =
17811785
NULL
17821786
#endif
17831787
},
1784-
{"term_setapi", 2, 2, FEARG_1, NULL,
1788+
{"term_setapi", 2, 2, FEARG_1, arg2_string_or_nr_string,
17851789
ret_void, TERM_FUNC(f_term_setapi)},
1786-
{"term_setkill", 2, 2, FEARG_1, NULL,
1790+
{"term_setkill", 2, 2, FEARG_1, arg2_string_or_nr_string,
17871791
ret_void, TERM_FUNC(f_term_setkill)},
1788-
{"term_setrestore", 2, 2, FEARG_1, NULL,
1792+
{"term_setrestore", 2, 2, FEARG_1, arg2_string_or_nr_string,
17891793
ret_void, TERM_FUNC(f_term_setrestore)},
17901794
{"term_setsize", 3, 3, FEARG_1, NULL,
17911795
ret_void, TERM_FUNC(f_term_setsize)},
17921796
{"term_start", 1, 2, FEARG_1, NULL,
17931797
ret_number, TERM_FUNC(f_term_start)},
1794-
{"term_wait", 1, 2, FEARG_1, NULL,
1798+
{"term_wait", 1, 2, FEARG_1, arg2_string_or_nr_nr,
17951799
ret_void, TERM_FUNC(f_term_wait)},
17961800
{"terminalprops", 0, 0, 0, NULL,
17971801
ret_dict_string, f_terminalprops},
@@ -2473,8 +2477,12 @@ f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
24732477
static void
24742478
f_char2nr(typval_T *argvars, typval_T *rettv)
24752479
{
2476-
if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
2480+
if (in_vim9script()
2481+
&& (check_for_string_arg(argvars, 0) == FAIL
2482+
|| (argvars[1].v_type != VAR_UNKNOWN
2483+
&& check_for_bool_arg(argvars, 1) == FAIL)))
24772484
return;
2485+
24782486
if (has_mbyte)
24792487
{
24802488
int utf8 = 0;
@@ -6304,6 +6312,17 @@ find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
63046312
rettv->vval.v_string = NULL;
63056313
}
63066314

6315+
if (in_vim9script()
6316+
&& ((argvars[0].v_type != VAR_STRING
6317+
&& argvars[0].v_type != VAR_LIST
6318+
&& check_for_string_arg(argvars, 0) == FAIL)
6319+
|| (check_for_string_arg(argvars, 1) == FAIL)
6320+
|| (argvars[2].v_type != VAR_UNKNOWN
6321+
&& (check_for_number_arg(argvars, 2) == FAIL
6322+
|| (argvars[3].v_type != VAR_UNKNOWN
6323+
&& check_for_number_arg(argvars, 3) == FAIL)))))
6324+
goto theend;
6325+
63076326
if (argvars[0].v_type == VAR_LIST)
63086327
{
63096328
if ((l = argvars[0].vval.v_list) == NULL)
@@ -8961,6 +8980,13 @@ f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
89618980

89628981
rettv_list_set(rettv, NULL);
89638982

8983+
if (in_vim9script()
8984+
&& ((argvars[0].v_type != VAR_STRING
8985+
&& argvars[0].v_type != VAR_NUMBER
8986+
&& check_for_string_arg(argvars, 0) == FAIL)
8987+
|| check_for_number_arg(argvars, 1) == FAIL))
8988+
return;
8989+
89648990
#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
89658991
lnum = tv_get_lnum(argvars); // -1 on type error
89668992
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)
90179043

90189044
rettv_list_set(rettv, NULL);
90199045

9046+
if (in_vim9script()
9047+
&& ((argvars[0].v_type != VAR_STRING
9048+
&& argvars[0].v_type != VAR_NUMBER
9049+
&& check_for_string_arg(argvars, 0) == FAIL)
9050+
|| check_for_number_arg(argvars, 1) == FAIL))
9051+
return;
9052+
90209053
#ifdef FEAT_SYN_HL
90219054
lnum = tv_get_lnum(argvars); // -1 on type error
90229055
col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error

src/globals.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1699,6 +1699,7 @@ EXTERN char e_readonlyvar[] INIT(= N_("E46: Cannot change read-only variable \"%
16991699
EXTERN char e_readonlysbx[] INIT(= N_("E794: Cannot set variable in the sandbox: \"%s\""));
17001700
EXTERN char e_stringreq[] INIT(= N_("E928: String required"));
17011701
EXTERN char e_numberreq[] INIT(= N_("E889: Number required"));
1702+
EXTERN char e_boolreq[] INIT(= N_("E839: Number required"));
17021703
EXTERN char e_emptykey[] INIT(= N_("E713: Cannot use empty key for Dictionary"));
17031704
EXTERN char e_dictreq[] INIT(= N_("E715: Dictionary required"));
17041705
EXTERN char e_listidx[] INIT(= N_("E684: list index out of range: %ld"));

src/job.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1725,6 +1725,13 @@ f_prompt_setprompt(typval_T *argvars, typval_T *rettv UNUSED)
17251725
buf_T *buf;
17261726
char_u *text;
17271727

1728+
if (in_vim9script()
1729+
&& ((argvars[0].v_type != VAR_STRING
1730+
&& argvars[0].v_type != VAR_NUMBER
1731+
&& check_for_string_arg(argvars, 0) == FAIL)
1732+
|| check_for_string_arg(argvars, 1) == FAIL))
1733+
return;
1734+
17281735
if (check_secure())
17291736
return;
17301737
buf = tv_get_buf(&argvars[0], FALSE);

src/proto/typval.pro

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ float_T tv_get_float(typval_T *varp);
1212
int check_for_string_arg(typval_T *args, int idx);
1313
int check_for_nonempty_string_arg(typval_T *args, int idx);
1414
int check_for_number_arg(typval_T *args, int idx);
15+
int check_for_bool_arg(typval_T *args, int idx);
16+
int check_for_list_arg(typval_T *args, int idx);
1517
int check_for_dict_arg(typval_T *args, int idx);
1618
char_u *tv_get_string(typval_T *varp);
1719
char_u *tv_get_string_strict(typval_T *varp);

src/strings.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -902,6 +902,12 @@ f_str2list(typval_T *argvars, typval_T *rettv)
902902
if (rettv_list_alloc(rettv) == FAIL)
903903
return;
904904

905+
if (in_vim9script()
906+
&& (check_for_string_arg(argvars, 0) == FAIL
907+
|| (argvars[1].v_type != VAR_UNKNOWN
908+
&& check_for_bool_arg(argvars, 1) == FAIL)))
909+
return;
910+
905911
if (argvars[1].v_type != VAR_UNKNOWN)
906912
utf8 = (int)tv_get_bool_chk(&argvars[1], NULL);
907913

@@ -1108,6 +1114,12 @@ f_strchars(typval_T *argvars, typval_T *rettv)
11081114
{
11091115
varnumber_T skipcc = FALSE;
11101116

1117+
if (in_vim9script()
1118+
&& (check_for_string_arg(argvars, 0) == FAIL
1119+
|| (argvars[1].v_type != VAR_UNKNOWN
1120+
&& check_for_bool_arg(argvars, 1) == FAIL)))
1121+
return;
1122+
11111123
if (argvars[1].v_type != VAR_UNKNOWN)
11121124
skipcc = tv_get_bool(&argvars[1]);
11131125
if (skipcc < 0 || skipcc > 1)

0 commit comments

Comments
 (0)