summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2020-07-26 17:56:25 +0200
committerBram Moolenaar <Bram@vim.org>2020-07-26 17:56:25 +0200
commit4fc224ca1cf2a8991c5ea17682a742c6ad5ad0f3 (patch)
tree4c752cc9133d073c9f0a085f94bdd38948598d7a
parent2547aa930b59f5e2bcb70e81d5a57ed461e59b4f (diff)
patch 8.2.1300: Vim9: optional argument type not parsed properlyv8.2.1300
Problem: Vim9: optional argument type not parsed properly. Solution: Skip over the "?". (issue #6507)
-rw-r--r--src/evalvars.c2
-rw-r--r--src/proto/vim9compile.pro2
-rw-r--r--src/testdir/test_vim9_func.vim13
-rw-r--r--src/userfunc.c4
-rw-r--r--src/version.c2
-rw-r--r--src/vim9compile.c25
6 files changed, 37 insertions, 11 deletions
diff --git a/src/evalvars.c b/src/evalvars.c
index e11fdac41f..f409f8c006 100644
--- a/src/evalvars.c
+++ b/src/evalvars.c
@@ -1013,7 +1013,7 @@ skip_var_one(char_u *arg, int include_type)
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
index 6bf3eb315d..4108c04af4 100644
--- a/src/proto/vim9compile.pro
+++ b/src/proto/vim9compile.pro
@@ -6,7 +6,7 @@ type_T *typval2type_vimvar(typval_T *tv, garray_T *type_gap);
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
index 49be8f97a2..ade1fd1459 100644
--- 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
index 3e566f334a..d17e807dc6 100644
--- a/src/userfunc.c
+++ b/src/userfunc.c
@@ -123,7 +123,7 @@ one_function_arg(char_u *arg, garray_T *newargs, garray_T *argtypes, int skip)
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_arg)
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
index 93bcc43247..68c7cf5013 100644
--- 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
index 746c9aa1a2..1354a38b2c 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -534,8 +534,16 @@ typval2type(typval_T *tv, garray_T *type_gap)
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);
}
}