Skip to content

Commit ec5929d

Browse files
committed
patch 8.2.0527: Vim9: function types insufficiently tested
Problem: Vim9: function types insufficiently tested. Solution: Add more tests. Fix white space check. Add "test_vim9" target.
1 parent 86b9a3e commit ec5929d

6 files changed

Lines changed: 101 additions & 36 deletions

File tree

src/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2301,7 +2301,7 @@ test1 \
23012301
# export TEST_FILTER=Test_terminal_wipe_buffer
23022302
# A partial match also works:
23032303
# export TEST_FILTER=wipe_buffer
2304-
$(NEW_TESTS):
2304+
$(NEW_TESTS) test_vim9:
23052305
cd testdir; $(MAKE) $@ VIMPROG=../$(VIMTESTTARGET) $(GUI_TESTARG) SCRIPTSOURCE=../$(SCRIPTSOURCE)
23062306

23072307
newtests:

src/testdir/Make_all.mak

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,19 @@ SCRIPTS_WIN32 =
4343
# Tests for the GUI.
4444
SCRIPTS_GUI =
4545

46+
# Tests for Vim9 script.
47+
TEST_VIM9 = \
48+
test_vim9_disassemble \
49+
test_vim9_expr \
50+
test_vim9_func \
51+
test_vim9_script
52+
53+
TEST_VIM9_RES = \
54+
test_vim9_disassemble.res \
55+
test_vim9_expr.res \
56+
test_vim9_func.res \
57+
test_vim9_script.res
58+
4659
# Individual tests, including the ones part of test_alot.
4760
# Please keep sorted up to test_alot.
4861
NEW_TESTS = \
@@ -272,10 +285,7 @@ NEW_TESTS = \
272285
test_utf8 \
273286
test_utf8_comparisons \
274287
test_vartabs \
275-
test_vim9_disassemble \
276-
test_vim9_expr \
277-
test_vim9_func \
278-
test_vim9_script \
288+
$(TEST_VIM9) \
279289
test_viminfo \
280290
test_vimscript \
281291
test_virtualedit \
@@ -482,10 +492,7 @@ NEW_TESTS_RES = \
482492
test_user_func.res \
483493
test_usercommands.res \
484494
test_vartabs.res \
485-
test_vim9_disassemble.res \
486-
test_vim9_expr.res \
487-
test_vim9_func.res \
488-
test_vim9_script.res \
495+
$(TEST_VIM9_RES) \
489496
test_viminfo.res \
490497
test_vimscript.res \
491498
test_virtualedit.res \

src/testdir/Makefile

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,16 @@ $(NEW_TESTS):
7979
exit 1; \
8080
fi
8181

82+
# Run only tests specific for Vim9 script
83+
test_vim9:
84+
rm -f test_vim9_*.res test.log messages
85+
@MAKEFLAGS=--no-print-directory $(MAKE) -f Makefile $(TEST_VIM9_RES) VIMPROG=$(VIMPROG) XXDPROG=$(XXDPROG) SCRIPTSOURCE=$(SCRIPTSOURCE)
86+
@cat messages
87+
@MAKEFLAGS=--no-print-directory $(MAKE) -f Makefile report VIMPROG=$(VIMPROG) XXDPROG=$(XXDPROG) SCRIPTSOURCE=$(SCRIPTSOURCE)
88+
@if test -f test.log; then \
89+
exit 1; \
90+
fi
91+
8292
RM_ON_RUN = test.out X* viminfo
8393
RM_ON_START = tiny.vim small.vim mbyte.vim mzscheme.vim test.ok benchmark.out
8494
RUN_VIM = VIMRUNTIME=$(SCRIPTSOURCE) $(VALGRIND) $(VIMPROG) -f $(GUI_FLAG) -u unix.vim $(NO_INITS) -s dotest.in

src/testdir/test_vim9_func.vim

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,11 @@ def FuncNoArgRetNumber(): number
373373
return 1234
374374
enddef
375375

376+
def FuncNoArgRetString(): string
377+
funcResult = 45
378+
return 'text'
379+
enddef
380+
376381
def FuncOneArgNoRet(arg: number)
377382
funcResult = arg
378383
enddef
@@ -382,6 +387,10 @@ def FuncOneArgRetNumber(arg: number): number
382387
return arg
383388
enddef
384389

390+
def FuncOneArgRetString(arg: string): string
391+
return arg
392+
enddef
393+
385394
def FuncOneArgRetAny(arg: any): any
386395
return arg
387396
enddef
@@ -415,6 +424,32 @@ def Test_func_type()
415424
assert_equal(13, funcResult)
416425
enddef
417426

427+
def Test_func_type_part()
428+
let RefVoid: func: void
429+
RefVoid = FuncNoArgNoRet
430+
RefVoid = FuncOneArgNoRet
431+
CheckDefFailure(['let RefVoid: func: void', 'RefVoid = FuncNoArgRetNumber'], 'E1013: type mismatch, expected func() but got func(): number')
432+
CheckDefFailure(['let RefVoid: func: void', 'RefVoid = FuncNoArgRetString'], 'E1013: type mismatch, expected func() but got func(): string')
433+
434+
let RefAny: func(): any
435+
RefAny = FuncNoArgRetNumber
436+
RefAny = FuncNoArgRetString
437+
CheckDefFailure(['let RefAny: func(): any', 'RefAny = FuncNoArgNoRet'], 'E1013: type mismatch, expected func(): any but got func()')
438+
CheckDefFailure(['let RefAny: func(): any', 'RefAny = FuncOneArgNoRet'], 'E1013: type mismatch, expected func(): any but got func(number)')
439+
440+
let RefNr: func: number
441+
RefNr = FuncNoArgRetNumber
442+
RefNr = FuncOneArgRetNumber
443+
CheckDefFailure(['let RefNr: func: number', 'RefNr = FuncNoArgNoRet'], 'E1013: type mismatch, expected func(): number but got func()')
444+
CheckDefFailure(['let RefNr: func: number', 'RefNr = FuncNoArgRetString'], 'E1013: type mismatch, expected func(): number but got func(): string')
445+
446+
let RefStr: func: string
447+
RefStr = FuncNoArgRetString
448+
RefStr = FuncOneArgRetString
449+
CheckDefFailure(['let RefStr: func: string', 'RefStr = FuncNoArgNoRet'], 'E1013: type mismatch, expected func(): string but got func()')
450+
CheckDefFailure(['let RefStr: func: string', 'RefStr = FuncNoArgRetNumber'], 'E1013: type mismatch, expected func(): string but got func(): number')
451+
enddef
452+
418453
def Test_func_type_fails()
419454
CheckDefFailure(['let ref1: func()'], 'E704:')
420455

src/version.c

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

739739
static int included_patches[] =
740740
{ /* Add new patch number below this line */
741+
/**/
742+
527,
741743
/**/
742744
526,
743745
/**/

src/vim9compile.c

Lines changed: 38 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,11 @@ get_func_type(type_T *ret_type, int argcount, garray_T *type_gap)
314314
// recognize commonly used types
315315
if (argcount <= 0)
316316
{
317+
if (ret_type == &t_unknown)
318+
{
319+
// (argcount == 0) is not possible
320+
return &t_func_unknown;
321+
}
317322
if (ret_type == &t_void)
318323
{
319324
if (argcount == 0)
@@ -350,6 +355,7 @@ get_func_type(type_T *ret_type, int argcount, garray_T *type_gap)
350355
return &t_any;
351356
type->tt_type = VAR_FUNC;
352357
type->tt_member = ret_type;
358+
type->tt_argcount = argcount;
353359
type->tt_args = NULL;
354360
return type;
355361
}
@@ -1589,7 +1595,7 @@ parse_type(char_u **arg, garray_T *type_gap)
15891595
if (len == 4 && STRNCMP(*arg, "func", len) == 0)
15901596
{
15911597
type_T *type;
1592-
type_T *ret_type = &t_any;
1598+
type_T *ret_type = &t_unknown;
15931599
int argcount = -1;
15941600
int flags = 0;
15951601
int first_optional = -1;
@@ -1657,7 +1663,7 @@ parse_type(char_u **arg, garray_T *type_gap)
16571663
{
16581664
// parse return type
16591665
++*arg;
1660-
if (!VIM_ISWHITE(*p))
1666+
if (!VIM_ISWHITE(**arg))
16611667
semsg(_(e_white_after), ":");
16621668
*arg = skipwhite(*arg);
16631669
ret_type = parse_type(arg, type_gap);
@@ -2405,7 +2411,10 @@ check_type(type_T *expected, type_T *actual, int give_msg)
24052411
{
24062412
int ret = OK;
24072413

2408-
if (expected->tt_type != VAR_UNKNOWN && expected->tt_type != VAR_ANY)
2414+
// When expected is "unknown" we accept any actual type.
2415+
// When expected is "any" we accept any actual type except "void".
2416+
if (expected->tt_type != VAR_UNKNOWN
2417+
&& (expected->tt_type != VAR_ANY || actual->tt_type == VAR_VOID))
24092418
{
24102419
if (expected->tt_type != actual->tt_type)
24112420
{
@@ -2421,8 +2430,7 @@ check_type(type_T *expected, type_T *actual, int give_msg)
24212430
}
24222431
else if (expected->tt_type == VAR_FUNC)
24232432
{
2424-
if (expected->tt_member != &t_any
2425-
&& expected->tt_member != &t_unknown)
2433+
if (expected->tt_member != &t_unknown)
24262434
ret = check_type(expected->tt_member, actual->tt_member, FALSE);
24272435
if (ret == OK && expected->tt_argcount != -1
24282436
&& (actual->tt_argcount < expected->tt_min_argcount
@@ -4044,36 +4052,39 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
40444052
if (r == FAIL)
40454053
goto theend;
40464054

4047-
stack = &cctx->ctx_type_stack;
4048-
stacktype = stack->ga_len == 0 ? &t_void
4049-
: ((type_T **)stack->ga_data)[stack->ga_len - 1];
4050-
if (idx >= 0 && (is_decl || !has_type))
4055+
if (cctx->ctx_skip != TRUE)
40514056
{
4052-
lvar = ((lvar_T *)cctx->ctx_locals.ga_data) + idx;
4053-
if (new_local && !has_type)
4057+
stack = &cctx->ctx_type_stack;
4058+
stacktype = stack->ga_len == 0 ? &t_void
4059+
: ((type_T **)stack->ga_data)[stack->ga_len - 1];
4060+
if (idx >= 0 && (is_decl || !has_type))
40544061
{
4055-
if (stacktype->tt_type == VAR_VOID)
4056-
{
4057-
emsg(_("E1031: Cannot use void value"));
4058-
goto theend;
4059-
}
4060-
else
4062+
lvar = ((lvar_T *)cctx->ctx_locals.ga_data) + idx;
4063+
if (new_local && !has_type)
40614064
{
4062-
// An empty list or dict has a &t_void member, for a
4063-
// variable that implies &t_any.
4064-
if (stacktype == &t_list_empty)
4065-
lvar->lv_type = &t_list_any;
4066-
else if (stacktype == &t_dict_empty)
4067-
lvar->lv_type = &t_dict_any;
4065+
if (stacktype->tt_type == VAR_VOID)
4066+
{
4067+
emsg(_("E1031: Cannot use void value"));
4068+
goto theend;
4069+
}
40684070
else
4069-
lvar->lv_type = stacktype;
4071+
{
4072+
// An empty list or dict has a &t_void member, for a
4073+
// variable that implies &t_any.
4074+
if (stacktype == &t_list_empty)
4075+
lvar->lv_type = &t_list_any;
4076+
else if (stacktype == &t_dict_empty)
4077+
lvar->lv_type = &t_dict_any;
4078+
else
4079+
lvar->lv_type = stacktype;
4080+
}
40704081
}
4082+
else if (need_type(stacktype, lvar->lv_type, -1, cctx) == FAIL)
4083+
goto theend;
40714084
}
4072-
else if (need_type(stacktype, lvar->lv_type, -1, cctx) == FAIL)
4085+
else if (*p != '=' && check_type(type, stacktype, TRUE) == FAIL)
40734086
goto theend;
40744087
}
4075-
else if (*p != '=' && check_type(type, stacktype, TRUE) == FAIL)
4076-
goto theend;
40774088
}
40784089
else if (cmdidx == CMD_const)
40794090
{

0 commit comments

Comments
 (0)