]> granicus.if.org Git - vim/commitdiff
patch 8.2.2740: Vim9: lambda with varargs doesn't work v8.2.2740
authorBram Moolenaar <Bram@vim.org>
Fri, 9 Apr 2021 18:24:31 +0000 (20:24 +0200)
committerBram Moolenaar <Bram@vim.org>
Fri, 9 Apr 2021 18:24:31 +0000 (20:24 +0200)
Problem:    Vim9: lambda with varargs doesn't work.
Solution:   Make "...name" work.  Require type to be a list.

src/errors.h
src/testdir/test_vim9_func.vim
src/testdir/test_vim9_script.vim
src/userfunc.c
src/version.c
src/vim9compile.c
src/vim9execute.c

index 0225531cb01fc966046b5cf9913783573295256f..e4836bc4acdc962c011eb1efe4266485c0f003f9 100644 (file)
@@ -395,3 +395,5 @@ EXTERN char e_cannot_lock_unlock_local_variable[]
        INIT(= N_("E1178: Cannot lock or unlock a local variable"));
 EXTERN char e_failed_to_extract_pwd_from_str_check_your_shell_config[]
        INIT(= N_("E1179: Failed to extract PWD from %s, check your shell's config related to OSC 7"));
+EXTERN char e_variable_arguments_type_must_be_list_str[]
+       INIT(= N_("E1180: Variable arguments type must be a list: %s"));
index b0669fe6515c87b9463ae54b152e6869241c2a8f..d48cab452e76102cfb771a0c231cf90a5e38ebb6 100644 (file)
@@ -791,10 +791,18 @@ def Test_call_funcref_wrong_args()
 enddef
 
 def Test_call_lambda_args()
+  var lines =<< trim END
+    var Callback = (..._) => 'anything'
+    assert_equal('anything', Callback())
+    assert_equal('anything', Callback(1))
+    assert_equal('anything', Callback('a', 2))
+  END
+  CheckDefAndScriptSuccess(lines)
+
   CheckDefFailure(['echo ((i) => 0)()'],
                   'E119: Not enough arguments for function: ((i) => 0)()')
 
-  var lines =<< trim END
+  lines =<< trim END
       var Ref = (x: number, y: number) => x + y
       echo Ref(1, 'x')
   END
@@ -923,13 +931,22 @@ def Test_call_def_varargs()
 
   lines =<< trim END
       vim9script
-      def Func(...l: any)
+      def Func(...l: list<any>)
         echo l
       enddef
       Func(0)
   END
   CheckScriptSuccess(lines)
 
+  lines =<< trim END
+      vim9script
+      def Func(...l: any)
+        echo l
+      enddef
+      Func(0)
+  END
+  CheckScriptFailure(lines, 'E1180:', 2)
+
   lines =<< trim END
       vim9script
       def Func(..._l: list<string>)
index 98f40bb8f91033e46fa4e0774671e85711b53953..7155e8f3b0205077471d1a665e739412c330d53c 100644 (file)
@@ -3644,7 +3644,7 @@ enddef
 def Test_catch_exception_in_callback()
   var lines =<< trim END
     vim9script
-    def Callback(...l: any)
+    def Callback(...l: list<any>)
       try
         var x: string
         var y: string
@@ -3669,10 +3669,10 @@ def Test_no_unknown_error_after_error()
   var lines =<< trim END
       vim9script
       var source: list<number>
-      def Out_cb(...l: any)
+      def Out_cb(...l: list<any>)
           eval [][0]
       enddef
-      def Exit_cb(...l: any)
+      def Exit_cb(...l: list<any>)
           sleep 1m
           source += l
       enddef
index 81a73e280314717dd06b23ca617317e3e94afde0..8d06b4916c2f3ffcc6c826925b0fcc302e7fd9ac 100644 (file)
@@ -68,6 +68,7 @@ one_function_arg(
        garray_T    *argtypes,
        int         types_optional,
        evalarg_T   *evalarg,
+       int         is_vararg,
        int         skip)
 {
     char_u     *p = arg;
@@ -155,7 +156,8 @@ one_function_arg(
        {
            if (type == NULL && types_optional)
                // lambda arguments default to "any" type
-               type = vim_strsave((char_u *)"any");
+               type = vim_strsave((char_u *)
+                                           (is_vararg ? "list<any>" : "any"));
            ((char_u **)argtypes->ga_data)[argtypes->ga_len++] = type;
        }
     }
@@ -250,7 +252,7 @@ get_function_args(
 
                arg = p;
                p = one_function_arg(p, newargs, argtypes, types_optional,
-                                                               evalarg, skip);
+                                                         evalarg, TRUE, skip);
                if (p == arg)
                    break;
                if (*skipwhite(p) == '=')
@@ -264,7 +266,7 @@ get_function_args(
        {
            arg = p;
            p = one_function_arg(p, newargs, argtypes, types_optional,
-                                                               evalarg, skip);
+                                                        evalarg, FALSE, skip);
            if (p == arg)
                break;
 
@@ -360,12 +362,14 @@ err_ret:
     static int
 parse_argument_types(ufunc_T *fp, garray_T *argtypes, int varargs)
 {
+    int len = 0;
+
     ga_init2(&fp->uf_type_list, sizeof(type_T *), 10);
     if (argtypes->ga_len > 0)
     {
        // When "varargs" is set the last name/type goes into uf_va_name
        // and uf_va_type.
-       int len = argtypes->ga_len - (varargs ? 1 : 0);
+       len = argtypes->ga_len - (varargs ? 1 : 0);
 
        if (len > 0)
            fp->uf_arg_types = ALLOC_CLEAR_MULT(type_T *, len);
@@ -388,25 +392,35 @@ parse_argument_types(ufunc_T *fp, garray_T *argtypes, int varargs)
                fp->uf_arg_types[i] = type;
            }
        }
-       if (varargs)
+    }
+
+    if (varargs)
+    {
+       char_u *p;
+
+       // Move the last argument "...name: type" to uf_va_name and
+       // uf_va_type.
+       fp->uf_va_name = ((char_u **)fp->uf_args.ga_data)
+                                             [fp->uf_args.ga_len - 1];
+       --fp->uf_args.ga_len;
+       p = ((char_u **)argtypes->ga_data)[len];
+       if (p == NULL)
+           // TODO: get type from default value
+           fp->uf_va_type = &t_list_any;
+       else
        {
-           char_u *p;
-
-           // Move the last argument "...name: type" to uf_va_name and
-           // uf_va_type.
-           fp->uf_va_name = ((char_u **)fp->uf_args.ga_data)
-                                                 [fp->uf_args.ga_len - 1];
-           --fp->uf_args.ga_len;
-           p = ((char_u **)argtypes->ga_data)[len];
-           if (p == NULL)
-               // todo: get type from default value
-               fp->uf_va_type = &t_any;
-           else
-               fp->uf_va_type = parse_type(&p, &fp->uf_type_list, TRUE);
-           if (fp->uf_va_type == NULL)
+           fp->uf_va_type = parse_type(&p, &fp->uf_type_list, TRUE);
+           if (fp->uf_va_type != NULL && fp->uf_va_type->tt_type != VAR_LIST)
+           {
+               semsg(_(e_variable_arguments_type_must_be_list_str),
+                                         ((char_u **)argtypes->ga_data)[len]);
                return FAIL;
+           }
        }
+       if (fp->uf_va_type == NULL)
+           return FAIL;
     }
+
     return OK;
 }
 
@@ -1236,7 +1250,8 @@ get_lambda_tv(
        ga_init(&fp->uf_def_args);
        if (types_optional)
        {
-           if (parse_argument_types(fp, &argtypes, FALSE) == FAIL)
+           if (parse_argument_types(fp, &argtypes,
+                                          in_vim9script() && varargs) == FAIL)
                goto errret;
            if (ret_type != NULL)
            {
@@ -1264,8 +1279,8 @@ get_lambda_tv(
        if (sandbox)
            flags |= FC_SANDBOX;
        // In legacy script a lambda can be called with more args than
-       // uf_args.ga_len.
-       fp->uf_varargs = !in_vim9script();
+       // uf_args.ga_len.  In Vim9 script "...name" has to be used.
+       fp->uf_varargs = !in_vim9script() || varargs;
        fp->uf_flags = flags;
        fp->uf_calls = 0;
        fp->uf_script_ctx = current_sctx;
@@ -3190,7 +3205,7 @@ list_func_head(ufunc_T *fp, int indent)
            msg_puts(", ");
        msg_puts("...");
        msg_puts((char *)fp->uf_va_name);
-       if (fp->uf_va_type)
+       if (fp->uf_va_type != NULL)
        {
            char *tofree;
 
index a2bd55869a833dc31d65261162c1154ad87d1d6a..74a0ae6e7f221b7e0bd18f19525bde74a544eb3e 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2740,
 /**/
     2739,
 /**/
index 00a8f56469a29610934b3e1f06cfeb317175fe1b..2cfc12798da7b9e298cbed59a4e5bca971052fdd 100644 (file)
@@ -1856,7 +1856,8 @@ generate_CALL(cctx_T *cctx, ufunc_T *ufunc, int pushed_argcount)
                    continue;
                expected = ufunc->uf_arg_types[i];
            }
-           else if (ufunc->uf_va_type == NULL || ufunc->uf_va_type == &t_any)
+           else if (ufunc->uf_va_type == NULL
+                                          || ufunc->uf_va_type == &t_list_any)
                // possibly a lambda or "...: any"
                expected = &t_any;
            else
@@ -9069,7 +9070,7 @@ set_function_type(ufunc_T *ufunc)
        if (varargs)
        {
            ufunc->uf_func_type->tt_args[argcount] =
-                   ufunc->uf_va_type == NULL ? &t_any : ufunc->uf_va_type;
+                  ufunc->uf_va_type == NULL ? &t_list_any : ufunc->uf_va_type;
            ufunc->uf_func_type->tt_flags = TTFLAG_VARARGS;
        }
     }
index d6c47648824267ae2f6421a4fb78fb0f671d782b..eddb90f9ffbaee54c153cca14099545e73bcde66 100644 (file)
@@ -1374,7 +1374,7 @@ call_def_function(
        // Check the type of the list items.
        tv = STACK_TV_BOT(-1);
        if (ufunc->uf_va_type != NULL
-               && ufunc->uf_va_type != &t_any
+               && ufunc->uf_va_type != &t_list_any
                && ufunc->uf_va_type->tt_member != &t_any
                && tv->vval.v_list != NULL)
        {