]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.1.1882: Vim9: Not able to use a lambda with :defer v9.1.1882
authorYegappan Lakshmanan <yegappan@yahoo.com>
Mon, 27 Oct 2025 18:07:52 +0000 (18:07 +0000)
committerChristian Brabandt <cb@256bit.org>
Mon, 27 Oct 2025 18:07:52 +0000 (18:07 +0000)
Problem:  Vim9: Not able to use a lambda with :defer
          (Maxim Kim)
Solution: Add support for this (Yegappan Lakshmanan)

fixes: #18626
closes: #18643

Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
runtime/doc/userfunc.txt
src/proto/vim9expr.pro
src/testdir/test_vim9_script.vim
src/version.c
src/vim9cmds.c
src/vim9expr.c

index 5b3605a147a67764d42dc7118fe4a7ae6dbb50c7..0f008446ee7bb5cd4126405da9b150d98bd613c9 100644 (file)
@@ -1,4 +1,4 @@
-*userfunc.txt* For Vim version 9.1.  Last change: 2025 Oct 12
+*userfunc.txt* For Vim version 9.1.  Last change: 2025 Oct 27
 
 
                  VIM REFERENCE MANUAL    by Bram Moolenaar
@@ -449,6 +449,15 @@ or altering execution outside of deferred functions.
 No range is accepted.  The function can be a partial with extra arguments, but
 not with a dictionary. *E1300*
 
+In a |:def| function, a lambda can be used with |:defer|.  Example: >
+
+    def Fn()
+      set lazyredraw
+      defer () => {
+        set lazyredraw&
+      }()
+    enddef
+<
 ==============================================================================
 
 4. Automatically loading functions ~
index 58c79fc0273cb54818ad5fe6a6b2857179e707db..4de1439179e00552ee1b83376c03081e8379e207 100644 (file)
@@ -7,6 +7,7 @@ int compile_load(char_u **arg, size_t namelen, char_u *end_arg, cctx_T *cctx, in
 int compile_arguments(char_u **arg, cctx_T *cctx, int *argcount, ca_special_T special_fn);
 char_u *to_name_end(char_u *arg, int use_namespace);
 char_u *to_name_const_end(char_u *arg);
+int compile_lambda(char_u **arg, cctx_T *cctx);
 int get_lambda_tv_and_compile(char_u **arg, typval_T *rettv, int types_optional, evalarg_T *evalarg);
 exprtype_T get_compare_type(char_u *p, int *len, int *type_is);
 void skip_expr_cctx(char_u **arg, cctx_T *cctx);
index 40832a606ce41f695062d0c516b6e74777f97559..0134956c301fe9502a3de928e5241d8b522e7213 100644 (file)
@@ -5249,6 +5249,102 @@ def Test_defer_lambda_funcref()
   v9.CheckSourceSuccess(lines)
 enddef
 
+" Test for using defer with a lambda and a command block
+def Test_defer_lambda_func()
+  var lines =<< trim END
+    vim9script
+    var result = ''
+    def Foo()
+      result = 'xxx'
+      defer (a: number, b: string): number => {
+        result = $'{a}:{b}'
+        return 0
+      }(10, 'aaa')
+      result = 'yyy'
+    enddef
+    Foo()
+    assert_equal('10:aaa', result)
+  END
+  v9.CheckScriptSuccess(lines)
+
+  # Error: argument type mismatch
+  lines =<< trim END
+    vim9script
+    def Foo()
+      defer (a: number, b: string): number => {
+        return 0
+      }(10, 20)
+    enddef
+    defcompile
+  END
+  v9.CheckScriptFailure(lines, 'E1013: Argument 2: type mismatch, expected string but got number', 1)
+
+  # Error: not enough arguments
+  lines =<< trim END
+    vim9script
+    def Foo()
+      defer (a: number) => {
+      }()
+    enddef
+    defcompile
+  END
+  v9.CheckScriptFailure(lines, 'E119: Not enough arguments for function: (a: number) => {', 1)
+
+  # Error: too many arguments
+  lines =<< trim END
+    vim9script
+    def Foo()
+      defer () => {
+      }(10)
+    enddef
+    defcompile
+  END
+  v9.CheckScriptFailure(lines, 'E118: Too many arguments for function: () => {', 1)
+
+  # Error: invalid command in command-block
+  lines =<< trim END
+    vim9script
+    def Foo()
+      defer () => {
+        xxx
+      }()
+    enddef
+    defcompile
+  END
+  v9.CheckScriptFailure(lines, 'E476: Invalid command: xxx', 1)
+
+  # Error: missing return
+  lines =<< trim END
+    vim9script
+    def Foo()
+      defer (): number => {
+      }()
+    enddef
+    defcompile
+  END
+  v9.CheckScriptFailure(lines, 'E1027: Missing return statement', 1)
+
+  # Error: missing lambda body
+  lines =<< trim END
+    vim9script
+    def Foo()
+      defer (a: number): number
+    enddef
+    defcompile
+  END
+  v9.CheckScriptFailure(lines, 'E1028: Compiling :def function failed', 1)
+
+  # Error: invalid lambda syntax
+  lines =<< trim END
+    vim9script
+    def Foo()
+      defer (
+    enddef
+    defcompile
+  END
+  v9.CheckScriptFailure(lines, 'E1028: Compiling :def function failed', 1)
+enddef
+
 " Test for using an non-existing type in a "for" statement.
 def Test_invalid_type_in_for()
   var lines =<< trim END
index b837e88f73b2d34b1c9469a85b3230e2651cfa5b..ed9059da4ad445dc392982abcfe0ebe51068edbe 100644 (file)
@@ -729,6 +729,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1882,
 /**/
     1881,
 /**/
index fb9f78137b6e3a8c28204e34ed1632db3a7eda2f..684d2ee66d643c53992eb5aae2fe557b53c059d4 100644 (file)
@@ -2040,25 +2040,35 @@ compile_defer(char_u *arg_start, cctx_T *cctx)
     int                argcount = 0;
     int                defer_var_idx;
     type_T     *type = NULL;
-    int                func_idx;
+    int                func_idx = -1;
 
-    // Get a funcref for the function name.
-    // TODO: better way to find the "(".
-    paren = vim_strchr(arg, '(');
-    if (paren == NULL)
+    if (*arg == '(')
     {
-       semsg(_(e_missing_parenthesis_str), arg);
-       return NULL;
+       // a lambda function
+       if (compile_lambda(&arg, cctx) != OK)
+           return NULL;
+       paren = arg;
+    }
+    else
+    {
+       // Get a funcref for the function name.
+       // TODO: better way to find the "(".
+       paren = vim_strchr(arg, '(');
+       if (paren == NULL)
+       {
+           semsg(_(e_missing_parenthesis_str), arg);
+           return NULL;
+       }
+       *paren = NUL;
+       func_idx = find_internal_func(arg);
+       if (func_idx >= 0)
+           // TODO: better type
+           generate_PUSHFUNC(cctx, (char_u *)internal_func_name(func_idx),
+                   &t_func_any, FALSE);
+       else if (compile_expr0(&arg, cctx) == FAIL)
+           return NULL;
+       *paren = '(';
     }
-    *paren = NUL;
-    func_idx = find_internal_func(arg);
-    if (func_idx >= 0)
-       // TODO: better type
-       generate_PUSHFUNC(cctx, (char_u *)internal_func_name(func_idx),
-                                                          &t_func_any, FALSE);
-    else if (compile_expr0(&arg, cctx) == FAIL)
-       return NULL;
-    *paren = '(';
 
     // check for function type
     if (cctx->ctx_skip != SKIP_YES)
index ab14afc335133804100ee72b6f128542077d1ed6..f692eeff30efda7f645904b4c3d33876e2123916 100644 (file)
@@ -1747,7 +1747,7 @@ compile_tuple(
  * "*arg" points to the '('.
  * Returns OK/FAIL when a lambda is recognized, NOTDONE if it's not a lambda.
  */
-    static int
+    int
 compile_lambda(char_u **arg, cctx_T *cctx)
 {
     int                r;