Skip to content

Commit 5bca906

Browse files
yegappanbrammool
authored andcommitted
patch 8.2.3215: 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. Sort the argument lists. (Yegappan Lakshmanan, closes #8626)
1 parent 7d60384 commit 5bca906

File tree

8 files changed

+223
-102
lines changed

8 files changed

+223
-102
lines changed

src/change.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,9 @@ f_listener_add(typval_T *argvars, typval_T *rettv)
241241
listener_T *lnr;
242242
buf_T *buf = curbuf;
243243

244+
if (in_vim9script() && check_for_opt_buffer_arg(argvars, 1) == FAIL)
245+
return;
246+
244247
callback = get_callback(&argvars[0]);
245248
if (callback.cb_name == NULL)
246249
return;

src/evalfunc.c

Lines changed: 112 additions & 77 deletions
Large diffs are not rendered by default.

src/filepath.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1602,6 +1602,13 @@ f_readdir(typval_T *argvars, typval_T *rettv)
16021602

16031603
if (rettv_list_alloc(rettv) == FAIL)
16041604
return;
1605+
1606+
if (in_vim9script()
1607+
&& (check_for_string_arg(argvars, 0) == FAIL
1608+
|| (argvars[1].v_type != VAR_UNKNOWN
1609+
&& check_for_opt_dict_arg(argvars, 2) == FAIL)))
1610+
return;
1611+
16051612
path = tv_get_string(&argvars[0]);
16061613
expr = &argvars[1];
16071614

@@ -1648,6 +1655,13 @@ f_readdirex(typval_T *argvars, typval_T *rettv)
16481655

16491656
if (rettv_list_alloc(rettv) == FAIL)
16501657
return;
1658+
1659+
if (in_vim9script()
1660+
&& (check_for_string_arg(argvars, 0) == FAIL
1661+
|| (argvars[1].v_type != VAR_UNKNOWN
1662+
&& check_for_opt_dict_arg(argvars, 2) == FAIL)))
1663+
return;
1664+
16511665
path = tv_get_string(&argvars[0]);
16521666
expr = &argvars[1];
16531667

src/sound.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,9 @@ invoke_sound_callback(void)
179179
static void
180180
sound_play_common(typval_T *argvars, typval_T *rettv, int playfile)
181181
{
182+
if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
183+
return;
184+
182185
if (context == NULL)
183186
ca_context_create(&context);
184187
if (context != NULL)
@@ -351,6 +354,9 @@ f_sound_playevent(typval_T *argvars, typval_T *rettv)
351354
{
352355
WCHAR *wp;
353356

357+
if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
358+
return;
359+
354360
wp = enc_to_utf16(tv_get_string(&argvars[0]), NULL);
355361
if (wp == NULL)
356362
return;
@@ -371,6 +377,9 @@ f_sound_playfile(typval_T *argvars, typval_T *rettv)
371377
char buf[32];
372378
MCIERROR err;
373379

380+
if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
381+
return;
382+
374383
esc = vim_strsave_shellescape(tv_get_string(&argvars[0]), FALSE, FALSE);
375384

376385
len = STRLEN(esc) + 5 + 18 + 1;

src/testdir/test_gui.vim

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1172,10 +1172,10 @@ endfunc
11721172
func Test_gui_drop_files()
11731173
CheckFeature drop_file
11741174

1175-
call assert_fails('call test_gui_drop_files(1, 1, 1, 0)', 'E474:')
1176-
call assert_fails('call test_gui_drop_files(["x"], "", 1, 0)', 'E474:')
1177-
call assert_fails('call test_gui_drop_files(["x"], 1, "", 0)', 'E474:')
1178-
call assert_fails('call test_gui_drop_files(["x"], 1, 1, "")', 'E474:')
1175+
call assert_fails('call test_gui_drop_files(1, 1, 1, 0)', 'E1211:')
1176+
call assert_fails('call test_gui_drop_files(["x"], "", 1, 0)', 'E1210:')
1177+
call assert_fails('call test_gui_drop_files(["x"], 1, "", 0)', 'E1210:')
1178+
call assert_fails('call test_gui_drop_files(["x"], 1, 1, "")', 'E1210:')
11791179

11801180
%bw!
11811181
%argdelete

src/testdir/test_vim9_builtin.vim

Lines changed: 70 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,8 @@ def Test_call_call()
373373
var l = [3, 2, 1]
374374
call('reverse', [l])
375375
l->assert_equal([1, 2, 3])
376+
CheckDefAndScriptFailure2(['call("reverse", 2)'], 'E1013: Argument 2: type mismatch, expected list<any> but got number', 'E1211: List required for argument 2')
377+
CheckDefAndScriptFailure2(['call("reverse", [2], [1])'], 'E1013: Argument 3: type mismatch, expected dict<any> but got list<number>', 'E1206: Dictionary required for argument 3')
376378
enddef
377379

378380
def Test_ch_canread()
@@ -1126,6 +1128,16 @@ def Test_fullcommand()
11261128
assert_equal('', fullcommand('scg'))
11271129
enddef
11281130

1131+
def Test_funcref()
1132+
CheckDefAndScriptFailure2(['funcref("reverse", 2)'], 'E1013: Argument 2: type mismatch, expected list<any> but got number', 'E1211: List required for argument 2')
1133+
CheckDefAndScriptFailure2(['funcref("reverse", [2], [1])'], 'E1013: Argument 3: type mismatch, expected dict<any> but got list<number>', 'E1206: Dictionary required for argument 3')
1134+
enddef
1135+
1136+
def Test_function()
1137+
CheckDefAndScriptFailure2(['function("reverse", 2)'], 'E1013: Argument 2: type mismatch, expected list<any> but got number', 'E1211: List required for argument 2')
1138+
CheckDefAndScriptFailure2(['function("reverse", [2], [1])'], 'E1013: Argument 3: type mismatch, expected dict<any> but got list<number>', 'E1206: Dictionary required for argument 3')
1139+
enddef
1140+
11291141
def Test_garbagecollect()
11301142
garbagecollect(true)
11311143
CheckDefAndScriptFailure2(['garbagecollect("1")'], 'E1013: Argument 1: type mismatch, expected bool but got string', 'E1135: Using a String as a Bool')
@@ -1691,6 +1703,20 @@ def Test_keys_return_type()
16911703
var->assert_equal(['a', 'b'])
16921704
enddef
16931705

1706+
def Test_libcall()
1707+
CheckFeature libcall
1708+
CheckDefAndScriptFailure2(['libcall(1, "b", 3)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1')
1709+
CheckDefAndScriptFailure2(['libcall("a", 2, 3)'], 'E1013: Argument 2: type mismatch, expected string but got number', 'E1174: String required for argument 2')
1710+
CheckDefAndScriptFailure2(['libcall("a", "b", 1.1)'], 'E1013: Argument 3: type mismatch, expected string but got float', 'E1174: String required for argument 3')
1711+
enddef
1712+
1713+
def Test_libcallnr()
1714+
CheckFeature libcall
1715+
CheckDefAndScriptFailure2(['libcallnr(1, "b", 3)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1')
1716+
CheckDefAndScriptFailure2(['libcallnr("a", 2, 3)'], 'E1013: Argument 2: type mismatch, expected string but got number', 'E1174: String required for argument 2')
1717+
CheckDefAndScriptFailure2(['libcallnr("a", "b", 1.1)'], 'E1013: Argument 3: type mismatch, expected string but got float', 'E1174: String required for argument 3')
1718+
enddef
1719+
16941720
def Test_line()
16951721
assert_fails('line(true)', 'E1174:')
16961722
CheckDefAndScriptFailure2(['line(1)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1')
@@ -1726,6 +1752,10 @@ def SID(): number
17261752
->str2nr()
17271753
enddef
17281754

1755+
def Test_listener_add()
1756+
CheckDefAndScriptFailure2(['listener_add("1", true)'], 'E1013: Argument 2: type mismatch, expected string but got bool', 'E1174: String required for argument 2')
1757+
enddef
1758+
17291759
def Test_listener_flush()
17301760
CheckDefAndScriptFailure2(['listener_flush([1])'], 'E1013: Argument 1: type mismatch, expected string but got list<number>', 'E730: Using a List as a String')
17311761
enddef
@@ -2285,8 +2315,15 @@ def Test_range()
22852315
enddef
22862316

22872317
def Test_readdir()
2288-
eval expand('sautest')->readdir((e) => e[0] !=# '.')
2289-
eval expand('sautest')->readdirex((e) => e.name[0] !=# '.')
2318+
eval expand('sautest')->readdir((e) => e[0] !=# '.')
2319+
eval expand('sautest')->readdirex((e) => e.name[0] !=# '.')
2320+
CheckDefAndScriptFailure2(['readdir(["a"])'], 'E1013: Argument 1: type mismatch, expected string but got list<string>', 'E1174: String required for argument 1')
2321+
CheckDefAndScriptFailure2(['readdir("a", "1", [3])'], 'E1013: Argument 3: type mismatch, expected dict<any> but got list<number>', 'E1206: Dictionary required for argument 3')
2322+
enddef
2323+
2324+
def Test_readdirex()
2325+
CheckDefAndScriptFailure2(['readdirex(["a"])'], 'E1013: Argument 1: type mismatch, expected string but got list<string>', 'E1174: String required for argument 1')
2326+
CheckDefAndScriptFailure2(['readdirex("a", "1", [3])'], 'E1013: Argument 3: type mismatch, expected dict<any> but got list<number>', 'E1206: Dictionary required for argument 3')
22902327
enddef
22912328

22922329
def Test_readblob()
@@ -2604,28 +2641,19 @@ def Test_searchpair()
26042641
CheckScriptSuccess(lines)
26052642
assert_equal('yes', g:caught)
26062643
unlet g:caught
2644+
bwipe!
26072645

26082646
lines =<< trim END
26092647
echo searchpair("a", "b", "c", "d", "f", 33)
26102648
END
26112649
CheckDefAndScriptFailure2(lines, 'E1001: Variable not found: f', 'E475: Invalid argument: d')
26122650

2613-
lines =<< trim END
2614-
def TestPair()
2615-
echo searchpair("a", "b", "c", "d", "1", 99)
2616-
enddef
2617-
defcompile
2618-
END
2619-
CheckScriptSuccess(lines)
2620-
2621-
bwipe!
26222651
CheckDefAndScriptFailure2(['searchpair(1, "b", "c")'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1')
26232652
CheckDefAndScriptFailure2(['searchpair("a", 2, "c")'], 'E1013: Argument 2: type mismatch, expected string but got number', 'E1174: String required for argument 2')
26242653
CheckDefAndScriptFailure2(['searchpair("a", "b", 3)'], 'E1013: Argument 3: type mismatch, expected string but got number', 'E1174: String required for argument 3')
26252654
CheckDefAndScriptFailure2(['searchpair("a", "b", "c", 4)'], 'E1013: Argument 4: type mismatch, expected string but got number', 'E1174: String required for argument 4')
2626-
# BUG: Vim crashes with the following test
2627-
#CheckDefAndScriptFailure2(['searchpair("a", "b", "c", "d", "1", "f")'], 'E1013: Argument 4: type mismatch, expected string but got number', 'E1174: String required for argument 4')
2628-
#CheckDefAndScriptFailure2(['searchpair("a", "b", "c", "d", "1", 3, "g")'], 'E1013: Argument 4: type mismatch, expected string but got number', 'E1174: String required for argument 4')
2655+
CheckDefAndScriptFailure2(['searchpair("a", "b", "c", "r", "1", "f")'], 'E1013: Argument 6: type mismatch, expected number but got string', 'E1210: Number required for argument 6')
2656+
CheckDefAndScriptFailure2(['searchpair("a", "b", "c", "r", "1", 3, "g")'], 'E1013: Argument 7: type mismatch, expected number but got string', 'E1210: Number required for argument 7')
26292657
enddef
26302658

26312659
def Test_searchpos()
@@ -2951,6 +2979,16 @@ def Test_spellsuggest()
29512979
CheckDefAndScriptFailure2(['spellsuggest("a", 1, 0z01)'], 'E1013: Argument 3: type mismatch, expected bool but got blob', 'E1212: Bool required for argument 3')
29522980
enddef
29532981

2982+
def Test_sound_playevent()
2983+
CheckFeature sound
2984+
CheckDefAndScriptFailure2(['sound_playevent(1)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1')
2985+
enddef
2986+
2987+
def Test_sound_playfile()
2988+
CheckFeature sound
2989+
CheckDefAndScriptFailure2(['sound_playfile(1)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1')
2990+
enddef
2991+
29542992
def Test_sound_stop()
29552993
CheckFeature sound
29562994
CheckDefFailure(['sound_stop("x")'], 'E1013: Argument 1: type mismatch, expected number but got string')
@@ -3137,6 +3175,9 @@ def Test_substitute()
31373175
assert_fails('"text"->substitute(".*", () => job_start(":"), "")', 'E908: using an invalid value as a String: job')
31383176
assert_fails('"text"->substitute(".*", () => job_start(":")->job_getchannel(), "")', 'E908: using an invalid value as a String: channel')
31393177
endif
3178+
CheckDefAndScriptFailure2(['substitute(1, "b", "1", "d")'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1')
3179+
CheckDefAndScriptFailure2(['substitute("a", 2, "1", "d")'], 'E1013: Argument 2: type mismatch, expected string but got number', 'E1174: String required for argument 2')
3180+
CheckDefAndScriptFailure2(['substitute("a", "b", "1", 4)'], 'E1013: Argument 4: type mismatch, expected string but got number', 'E1174: String required for argument 4')
31403181
enddef
31413182

31423183
def Test_swapinfo()
@@ -3376,6 +3417,14 @@ def Test_test_getvalue()
33763417
CheckDefAndScriptFailure2(['test_getvalue(1.1)'], 'E1013: Argument 1: type mismatch, expected string but got float', 'E474: Invalid argument')
33773418
enddef
33783419

3420+
def Test_test_gui_drop_files()
3421+
CheckGui
3422+
CheckDefAndScriptFailure2(['test_gui_drop_files("a", 1, 1, 0)'], 'E1013: Argument 1: type mismatch, expected list<string> but got string', 'E1211: List required for argument 1')
3423+
CheckDefAndScriptFailure2(['test_gui_drop_files(["x"], "", 1, 0)'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2')
3424+
CheckDefAndScriptFailure2(['test_gui_drop_files(["x"], 1, "", 0)'], 'E1013: Argument 3: type mismatch, expected number but got string', 'E1210: Number required for argument 3')
3425+
CheckDefAndScriptFailure2(['test_gui_drop_files(["x"], 1, 1, "")'], 'E1013: Argument 4: type mismatch, expected number but got string', 'E1210: Number required for argument 4')
3426+
enddef
3427+
33793428
def Test_test_gui_mouse_event()
33803429
CheckGui
33813430
CheckDefAndScriptFailure2(['test_gui_mouse_event(1.1, 1, 1, 1, 1)'], 'E1013: Argument 1: type mismatch, expected number but got float', 'E1210: Number required for argument 1')
@@ -3399,6 +3448,13 @@ def Test_test_override()
33993448
CheckDefAndScriptFailure2(['test_override("a", "x")'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2')
34003449
enddef
34013450

3451+
def Test_test_scrollbar()
3452+
CheckGui
3453+
CheckDefAndScriptFailure2(['test_scrollbar(1, 2, 3)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1')
3454+
CheckDefAndScriptFailure2(['test_scrollbar("a", "b", 3)'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2')
3455+
CheckDefAndScriptFailure2(['test_scrollbar("a", 2, "c")'], 'E1013: Argument 3: type mismatch, expected number but got string', 'E1210: Number required for argument 3')
3456+
enddef
3457+
34023458
def Test_test_setmouse()
34033459
CheckDefAndScriptFailure2(['test_setmouse("a", 10)'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E474: Invalid argument')
34043460
CheckDefAndScriptFailure2(['test_setmouse(10, "b")'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E474: Invalid argument')

src/testing.c

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1193,6 +1193,11 @@ f_test_scrollbar(typval_T *argvars, typval_T *rettv UNUSED)
11931193
int dragging;
11941194
scrollbar_T *sb = NULL;
11951195

1196+
if (check_for_string_arg(argvars, 0) == FAIL
1197+
|| check_for_number_arg(argvars, 1) == FAIL
1198+
|| check_for_number_arg(argvars, 2) == FAIL)
1199+
return;
1200+
11961201
if (argvars[0].v_type != VAR_STRING
11971202
|| (argvars[1].v_type) != VAR_NUMBER
11981203
|| (argvars[2].v_type) != VAR_NUMBER)
@@ -1281,14 +1286,11 @@ f_test_gui_drop_files(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12811286
list_T *l;
12821287
listitem_T *li;
12831288

1284-
if (argvars[0].v_type != VAR_LIST
1285-
|| (argvars[1].v_type) != VAR_NUMBER
1286-
|| (argvars[2].v_type) != VAR_NUMBER
1287-
|| (argvars[3].v_type) != VAR_NUMBER)
1288-
{
1289-
emsg(_(e_invarg));
1289+
if (check_for_list_arg(argvars, 0) == FAIL
1290+
|| check_for_number_arg(argvars, 1) == FAIL
1291+
|| check_for_number_arg(argvars, 2) == FAIL
1292+
|| check_for_number_arg(argvars, 3) == FAIL)
12901293
return;
1291-
}
12921294

12931295
row = tv_get_number(&argvars[1]);
12941296
col = tv_get_number(&argvars[2]);

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -755,6 +755,8 @@ static char *(features[]) =
755755

756756
static int included_patches[] =
757757
{ /* Add new patch number below this line */
758+
/**/
759+
3215,
758760
/**/
759761
3214,
760762
/**/

0 commit comments

Comments
 (0)