# HG changeset patch # User Bram Moolenaar # Date 1653600605 -7200 # Node ID 49d8b54802f38909d1cc9c70d1aa4b06a76b1270 # Parent 0e8c870971f7f4c9ae5e28282ea25ae05d56e146 patch 8.2.5026: Vim9: a few lines not covered by tests Commit: https://github.com/vim/vim/commit/31d9948e3a2529c2f619d56bdb48291dc261233d Author: Bram Moolenaar Date: Thu May 26 22:24:43 2022 +0100 patch 8.2.5026: Vim9: a few lines not covered by tests Problem: Vim9: a few lines not covered by tests. Solution: Delete dead code. Add a few test cases. make "12->func()" work. diff --git a/src/ex_docmd.c b/src/ex_docmd.c --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -3507,6 +3507,18 @@ one_letter_cmd(char_u *p, cmdidx_T *idx) } /* + * Return TRUE if "cmd" starts with "123->", a number followed by a method + * call. + */ + int +number_method(char_u *cmd) +{ + char_u *p = skipdigits(cmd); + + return p > cmd && (p = skipwhite(p))[0] == '-' && p[1] == '>'; +} + +/* * Find an Ex command by its name, either built-in or user. * Start of the name can be found at eap->cmd. * Sets eap->cmdidx and returns a pointer to char after the command name. @@ -3716,6 +3728,13 @@ find_ex_command( } } + // 1234->func() is a method call + if (number_method(eap->cmd)) + { + eap->cmdidx = CMD_eval; + return eap->cmd; + } + // "g:", "s:" and "l:" are always assumed to be a variable, thus start // an expression. A global/substitute/list command needs to use a // longer name. diff --git a/src/proto/ex_docmd.pro b/src/proto/ex_docmd.pro --- a/src/proto/ex_docmd.pro +++ b/src/proto/ex_docmd.pro @@ -17,6 +17,7 @@ void apply_cmdmod(cmdmod_T *cmod); void undo_cmdmod(cmdmod_T *cmod); int parse_cmd_address(exarg_T *eap, char **errormsg, int silent); char_u *skip_option_env_lead(char_u *start); +int number_method(char_u *cmd); char_u *find_ex_command(exarg_T *eap, int *full, int (*lookup)(char_u *, size_t, int cmd, cctx_T *), cctx_T *cctx); int modifier_len(char_u *cmd); int cmd_exists(char_u *name); diff --git a/src/testdir/test_vim9_assign.vim b/src/testdir/test_vim9_assign.vim --- a/src/testdir/test_vim9_assign.vim +++ b/src/testdir/test_vim9_assign.vim @@ -1121,6 +1121,9 @@ def Test_assignment_dict() var dict4: dict = {one: 1, two: '2'} var dict5: dict = {one: 0z01, two: 0z02} + # check the type is OK + var events: dict = v:event + # overwrite dict3['key'] = 'another' assert_equal(dict3, {key: 'another'}) @@ -2105,6 +2108,32 @@ def Test_var_declaration_fails() va foo = 123 END v9.CheckDefAndScriptFailure(lines, 'E1065:', 1) + + lines =<< trim END + var foo: func(number + END + v9.CheckDefAndScriptFailure(lines, 'E110:', 1) + + lines =<< trim END + var foo: func(number): func( + END + v9.CheckDefAndScriptFailure(lines, 'E110:', 1) + + for type in ['num_ber', + 'anys', 'ani', + 'bools', 'boel', + 'blobs', 'blub', + 'channels', 'channol', + 'dicts', 'duct', + 'floats', 'floot', + 'funcs', 'funk', + 'jobs', 'jop', + 'lists', 'last' + 'numbers', 'numbar', + 'strings', 'strung', + 'voids', 'viod'] + v9.CheckDefAndScriptFailure([$'var foo: {type}'], 'E1010:', 1) + endfor enddef def Test_var_declaration_inferred() @@ -2118,6 +2147,34 @@ def Test_var_declaration_inferred() echo GetList()->extend(['x']) END v9.CheckScriptFailure(lines, 'E1013:', 6) + + lines =<< trim END + vim9script + def GetNr(): number + return 5 + enddef + def TestOne() + var some = [function('len'), GetNr] + g:res = typename(some) + enddef + TestOne() + assert_equal('list', g:res) + + def TestTwo() + var some = [function('len'), GetNr] + g:res = typename(some) + enddef + TestTwo() + assert_equal('list', g:res) + unlet g:res + + # FIXME: why is the type different? + var first = [function('len'), GetNr] + assert_equal('list', typename(first)) + var second = [GetNr, function('len')] + assert_equal('list', typename(second)) + END + v9.CheckScriptSuccess(lines) enddef def Test_script_local_in_legacy() diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -4051,6 +4051,63 @@ def Test_too_many_arguments() echo [0, 1, 2]->map((_) => 123) END v9.CheckDefAndScriptFailure(lines, ['E176', 'E1106: One argument too many'], 1) + + lines =<< trim END + vim9script + def OneArgument(arg: string) + echo arg + enddef + var Ref = OneArgument + Ref('a', 'b') + END + v9.CheckScriptFailure(lines, 'E118:') +enddef + +def Test_funcref_with_base() + var lines =<< trim END + vim9script + def TwoArguments(str: string, nr: number) + echo str nr + enddef + var Ref = TwoArguments + Ref('a', 12) + 'b'->Ref(34) + END + v9.CheckScriptSuccess(lines) + + lines =<< trim END + vim9script + def TwoArguments(str: string, nr: number) + echo str nr + enddef + var Ref = TwoArguments + 'a'->Ref('b') + END + v9.CheckScriptFailure(lines, 'E1013: Argument 2: type mismatch, expected number but got string', 6) + + lines =<< trim END + vim9script + def TwoArguments(str: string, nr: number) + echo str nr + enddef + var Ref = TwoArguments + 123->Ref(456) + END + v9.CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected string but got number') + + lines =<< trim END + vim9script + def TwoArguments(nr: number, str: string) + echo str nr + enddef + var Ref = TwoArguments + 123->Ref('b') + def AndNowCompiled() + 456->Ref('x') + enddef + AndNowCompiled() + END + v9.CheckScriptSuccess(lines) enddef def Test_closing_brace_at_start_of_line() diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -735,6 +735,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 5026, +/**/ 5025, /**/ 5024, diff --git a/src/vim9compile.c b/src/vim9compile.c --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -3001,6 +3001,7 @@ compile_def_function( * 0z1234->func() should not be confused with a zero line number * "++nr" and "--nr" are eval commands * in "$ENV->func()" the "$" is not a range + * "123->func()" is a method call */ cmd = ea.cmd; if ((*cmd != '$' || starts_with_colon) @@ -3008,7 +3009,8 @@ compile_def_function( || !(*cmd == '\'' || (cmd[0] == '0' && cmd[1] == 'z') || (cmd[0] != NUL && cmd[0] == cmd[1] - && (*cmd == '+' || *cmd == '-'))))) + && (*cmd == '+' || *cmd == '-')) + || number_method(cmd)))) { ea.cmd = skip_range(ea.cmd, TRUE, NULL); if (ea.cmd > cmd) diff --git a/src/vim9type.c b/src/vim9type.c --- a/src/vim9type.c +++ b/src/vim9type.c @@ -244,48 +244,44 @@ alloc_func_type(type_T *ret_type, int ar /* * Get a function type, based on the return type "ret_type". - * If "argcount" is -1 or 0 a predefined type can be used. - * If "argcount" > 0 always create a new type, so that arguments can be added. + * "argcount" must be -1 or 0, a predefined type can be used. */ type_T * get_func_type(type_T *ret_type, int argcount, garray_T *type_gap) { // recognize commonly used types - if (argcount <= 0) + if (ret_type == &t_unknown || ret_type == NULL) + { + // (argcount == 0) is not possible + return &t_func_unknown; + } + if (ret_type == &t_void) + { + if (argcount == 0) + return &t_func_0_void; + else + return &t_func_void; + } + if (ret_type == &t_any) { - if (ret_type == &t_unknown || ret_type == NULL) - { - // (argcount == 0) is not possible - return &t_func_unknown; - } - if (ret_type == &t_void) - { - if (argcount == 0) - return &t_func_0_void; - else - return &t_func_void; - } - if (ret_type == &t_any) - { - if (argcount == 0) - return &t_func_0_any; - else - return &t_func_any; - } - if (ret_type == &t_number) - { - if (argcount == 0) - return &t_func_0_number; - else - return &t_func_number; - } - if (ret_type == &t_string) - { - if (argcount == 0) - return &t_func_0_string; - else - return &t_func_string; - } + if (argcount == 0) + return &t_func_0_any; + else + return &t_func_any; + } + if (ret_type == &t_number) + { + if (argcount == 0) + return &t_func_0_number; + else + return &t_func_number; + } + if (ret_type == &t_string) + { + if (argcount == 0) + return &t_func_0_string; + else + return &t_func_string; } return alloc_func_type(ret_type, argcount, type_gap); @@ -541,7 +537,7 @@ typval2type_vimvar(typval_T *tv, garray_ { if (tv->v_type == VAR_LIST) // e.g. for v:oldfiles return &t_list_string; - if (tv->v_type == VAR_DICT) // e.g. for v:completed_item + if (tv->v_type == VAR_DICT) // e.g. for v:event return &t_dict_any; return typval2type(tv, get_copyID(), type_gap, TVTT_DO_MEMBER); } @@ -1441,6 +1437,7 @@ vartype_name(vartype_T type) type_name(type_T *type, char **tofree) { char *name; + char *arg_free = NULL; *tofree = NULL; if (type == NULL) @@ -1469,13 +1466,12 @@ type_name(type_T *type, char **tofree) ga_init2(&ga, 1, 100); if (ga_grow(&ga, 20) == FAIL) - return "[unknown]"; + goto failed; STRCPY(ga.ga_data, "func("); ga.ga_len += 5; for (i = 0; i < type->tt_argcount; ++i) { - char *arg_free = NULL; char *arg_type; int len; @@ -1490,17 +1486,13 @@ type_name(type_T *type, char **tofree) } len = (int)STRLEN(arg_type); if (ga_grow(&ga, len + 8) == FAIL) - { - vim_free(arg_free); - ga_clear(&ga); - return "[unknown]"; - } + goto failed; if (varargs && i == type->tt_argcount - 1) ga_concat(&ga, (char_u *)"..."); else if (i >= type->tt_min_argcount) *((char *)ga.ga_data + ga.ga_len++) = '?'; ga_concat(&ga, (char_u *)arg_type); - vim_free(arg_free); + VIM_CLEAR(arg_free); } if (type->tt_argcount < 0) // any number of arguments @@ -1516,17 +1508,18 @@ type_name(type_T *type, char **tofree) len = (int)STRLEN(ret_name) + 4; if (ga_grow(&ga, len) == FAIL) - { - vim_free(ret_free); - ga_clear(&ga); - return "[unknown]"; - } + goto failed; STRCPY((char *)ga.ga_data + ga.ga_len, "): "); STRCPY((char *)ga.ga_data + ga.ga_len + 3, ret_name); vim_free(ret_free); } *tofree = ga.ga_data; return ga.ga_data; + +failed: + vim_free(arg_free); + ga_clear(&ga); + return "[unknown]"; } return name;