# HG changeset patch # User Bram Moolenaar # Date 1595779204 -7200 # Node ID 574517d682cf32652cb97f296829518a6ef2d98f # Parent 3a1ed539ae2abd135c97b6639ebe94cbcd87450d patch 8.2.1300: Vim9: optional argument type not parsed properly Commit: https://github.com/vim/vim/commit/4fc224ca1cf2a8991c5ea17682a742c6ad5ad0f3 Author: Bram Moolenaar Date: Sun Jul 26 17:56:25 2020 +0200 patch 8.2.1300: Vim9: optional argument type not parsed properly Problem: Vim9: optional argument type not parsed properly. Solution: Skip over the "?". (issue https://github.com/vim/vim/issues/6507) diff --git a/src/evalvars.c b/src/evalvars.c --- a/src/evalvars.c +++ b/src/evalvars.c @@ -1013,7 +1013,7 @@ skip_var_one(char_u *arg, int include_ty if (end == arg + 2 && end[-1] == ':') --end; if (*end == ':') - end = skip_type(skipwhite(end + 1)); + end = skip_type(skipwhite(end + 1), FALSE); } return end; } diff --git a/src/proto/vim9compile.pro b/src/proto/vim9compile.pro --- a/src/proto/vim9compile.pro +++ b/src/proto/vim9compile.pro @@ -6,7 +6,7 @@ type_T *typval2type_vimvar(typval_T *tv, int check_typval_type(type_T *expected, typval_T *actual_tv); int check_type(type_T *expected, type_T *actual, int give_msg); int check_compare_types(exptype_T type, typval_T *tv1, typval_T *tv2); -char_u *skip_type(char_u *start); +char_u *skip_type(char_u *start, int optional); type_T *parse_type(char_u **arg, garray_T *type_gap); char *vartype_name(vartype_T type); char *type_name(type_T *type, char **tofree); 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 @@ -350,6 +350,19 @@ def Test_call_funcref() let Funcref: func(string) = function('UseNumber') END CheckScriptFailure(lines, 'E1013: type mismatch, expected func(string) but got func(number)') + + lines =<< trim END + vim9script + def EchoNr(nr = 34) + g:echo = nr + enddef + let Funcref: func(?number) = function('EchoNr') + Funcref() + assert_equal(34, g:echo) + Funcref(123) + assert_equal(123, g:echo) + END + CheckScriptSuccess(lines) enddef let SomeFunc = function('len') diff --git a/src/userfunc.c b/src/userfunc.c --- a/src/userfunc.c +++ b/src/userfunc.c @@ -123,7 +123,7 @@ one_function_arg(char_u *arg, garray_T * return arg; } type = skipwhite(p); - p = skip_type(type); + p = skip_type(type, TRUE); type = vim_strnsave(type, p - type); } else if (*skipwhite(p) != '=') @@ -2778,7 +2778,7 @@ def_function(exarg_T *eap, char_u *name_ if (*p == ':') { ret_type = skipwhite(p + 1); - p = skip_type(ret_type); + p = skip_type(ret_type, FALSE); if (p > ret_type) { ret_type = vim_strnsave(ret_type, p - ret_type); diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1300, +/**/ 1299, /**/ 1298, diff --git a/src/vim9compile.c b/src/vim9compile.c --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -534,8 +534,16 @@ typval2type(typval_T *tv, garray_T *type if (name != NULL) // TODO: how about a builtin function? ufunc = find_func(name, FALSE, NULL); - if (ufunc != NULL && ufunc->uf_func_type != NULL) - return ufunc->uf_func_type; + if (ufunc != NULL) + { + // May need to get the argument types from default values by + // compiling the function. + if (ufunc->uf_def_status == UF_TO_BE_COMPILED + && compile_def_function(ufunc, TRUE, NULL) == FAIL) + return NULL; + if (ufunc->uf_func_type != NULL) + return ufunc->uf_func_type; + } } actual = alloc_type(type_gap); @@ -1916,12 +1924,15 @@ free_locals(cctx_T *cctx) /* * Skip over a type definition and return a pointer to just after it. + * When "optional" is TRUE then a leading "?" is accepted. */ char_u * -skip_type(char_u *start) +skip_type(char_u *start, int optional) { char_u *p = start; + if (optional && *p == '?') + ++p; while (ASCII_ISALNUM(*p) || *p == '_') ++p; @@ -1929,7 +1940,7 @@ skip_type(char_u *start) if (*skipwhite(p) == '<') { p = skipwhite(p); - p = skip_type(skipwhite(p + 1)); + p = skip_type(skipwhite(p + 1), FALSE); p = skipwhite(p); if (*p == '>') ++p; @@ -1945,7 +1956,7 @@ skip_type(char_u *start) { char_u *sp = p; - p = skip_type(p); + p = skip_type(p, TRUE); if (p == sp) return p; // syntax error if (*p == ',') @@ -1954,7 +1965,7 @@ skip_type(char_u *start) if (*p == ')') { if (p[1] == ':') - p = skip_type(skipwhite(p + 2)); + p = skip_type(skipwhite(p + 2), FALSE); else ++p; } @@ -1962,7 +1973,7 @@ skip_type(char_u *start) else { // handle func: return_type - p = skip_type(skipwhite(p + 1)); + p = skip_type(skipwhite(p + 1), FALSE); } }