]> granicus.if.org Git - vim/commitdiff
patch 8.2.1300: Vim9: optional argument type not parsed properly v8.2.1300
authorBram Moolenaar <Bram@vim.org>
Sun, 26 Jul 2020 15:56:25 +0000 (17:56 +0200)
committerBram Moolenaar <Bram@vim.org>
Sun, 26 Jul 2020 15:56:25 +0000 (17:56 +0200)
Problem:    Vim9: optional argument type not parsed properly.
Solution:   Skip over the "?". (issue #6507)

src/evalvars.c
src/proto/vim9compile.pro
src/testdir/test_vim9_func.vim
src/userfunc.c
src/version.c
src/vim9compile.c

index e11fdac41fb3af1d4926112ca5f764da2f3232df..f409f8c0066a1f9348614f15c7273908ed27cd26 100644 (file)
@@ -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;
 }
index 6bf3eb315d3d05af1c3bd2ee271a64d800811a46..4108c04af4eb09aedb7afbc326f2191687590af7 100644 (file)
@@ -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);
index 49be8f97a2527eb872cc78521e1bc9249448c51c..ade1fd145914c78c8bca89f9edc48bf9a0346e7b 100644 (file)
@@ -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')
index 3e566f334a741304a33181d1b92101e15a838358..d17e807dc616ceb58761fdf5f6ef02f3aa275baa 100644 (file)
@@ -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);
index 93bcc43247dc575de5353db20be4a0e4a424c080..68c7cf5013512b6d279f57a8e3b3bb6a0e740b53 100644 (file)
@@ -754,6 +754,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1300,
 /**/
     1299,
 /**/
index 746c9aa1a2d5b79ab47f174d2c4624c4c2e619de..1354a38b2c79a18ead95b37505c81fef918be96c 100644 (file)
@@ -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);
        }
     }