changeset 26348:bf1a7ce3f14a v8.2.3705

patch 8.2.3705: cannot pass a lambda name to function() or funcref() Commit: https://github.com/vim/vim/commit/eba3b7f6645c8f856132b4c06a009a3b0a44e21c Author: Bram Moolenaar <Bram@vim.org> Date: Tue Nov 30 18:25:08 2021 +0000 patch 8.2.3705: cannot pass a lambda name to function() or funcref() Problem: Cannot pass a lambda name to function() or funcref(). (Yegappan Lakshmanan) Solution: Handle a lambda name differently.
author Bram Moolenaar <Bram@vim.org>
date Tue, 30 Nov 2021 19:30:05 +0100
parents cd04fa8a6d91
children 2ee2e3e3097a
files src/evalfunc.c src/proto/userfunc.pro src/testdir/test_expr.vim src/userfunc.c src/version.c
diffstat 5 files changed, 44 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -3955,9 +3955,8 @@ common_function(typval_T *argvars, typva
     if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
     {
 	name = s;
-	trans_name = trans_function_name(&name, &is_global, FALSE,
-	     TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF,
-							     NULL, NULL, NULL);
+	trans_name = save_function_name(&name, &is_global, FALSE,
+		   TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL);
 	if (*name != NUL)
 	    s = NULL;
     }
--- a/src/proto/userfunc.pro
+++ b/src/proto/userfunc.pro
@@ -33,6 +33,7 @@ int call_func(char_u *funcname, int len,
 char_u *printable_func_name(ufunc_T *fp);
 char_u *trans_function_name(char_u **pp, int *is_global, int skip, int flags, funcdict_T *fdp, partial_T **partial, type_T **type);
 char_u *untrans_function_name(char_u *name);
+char_u *save_function_name(char_u **name, int *is_global, int skip, int flags, funcdict_T *fudi);
 void list_functions(regmatch_T *regmatch);
 ufunc_T *define_function(exarg_T *eap, char_u *name_arg);
 void ex_function(exarg_T *eap);
--- a/src/testdir/test_expr.vim
+++ b/src/testdir/test_expr.vim
@@ -547,6 +547,13 @@ func Test_function_with_funcref()
   call assert_fails("call function('foo()')", 'E475:')
   call assert_fails("call function('foo()')", 'foo()')
   call assert_fails("function('')", 'E129:')
+
+  let Len = {s -> strlen(s)}
+  call assert_equal(6, Len('foobar'))
+  let name = string(Len)
+  " can evaluate "function('<lambda>99')"
+  call execute('let Ref = ' .. name)
+  call assert_equal(4, Ref('text'))
 endfunc
 
 func Test_funcref()
--- a/src/userfunc.c
+++ b/src/userfunc.c
@@ -3811,6 +3811,36 @@ untrans_function_name(char_u *name)
 }
 
 /*
+ * Call trans_function_name(), except that a lambda is returned as-is.
+ * Returns the name in allocated memory.
+ */
+    char_u *
+save_function_name(
+	char_u	    **name,
+	int	    *is_global,
+	int	    skip,
+	int	    flags,
+	funcdict_T  *fudi)
+{
+    char_u *p = *name;
+    char_u *saved;
+
+    if (STRNCMP(p, "<lambda>", 8) == 0)
+    {
+	p += 8;
+	(void)getdigits(&p);
+	saved = vim_strnsave(*name, p - *name);
+	if (fudi != NULL)
+	    CLEAR_POINTER(fudi);
+    }
+    else
+	saved = trans_function_name(&p, is_global, skip,
+						      flags, fudi, NULL, NULL);
+    *name = p;
+    return saved;
+}
+
+/*
  * List functions.  When "regmatch" is NULL all of then.
  * Otherwise functions matching "regmatch".
  */
@@ -3950,16 +3980,8 @@ define_function(exarg_T *eap, char_u *na
     }
     else
     {
-	if (STRNCMP(p, "<lambda>", 8) == 0)
-	{
-	    p += 8;
-	    (void)getdigits(&p);
-	    name = vim_strnsave(eap->arg, p - eap->arg);
-	    CLEAR_FIELD(fudi);
-	}
-	else
-	    name = trans_function_name(&p, &is_global, eap->skip,
-					   TFN_NO_AUTOLOAD, &fudi, NULL, NULL);
+	name = save_function_name(&p, &is_global, eap->skip,
+						       TFN_NO_AUTOLOAD, &fudi);
 	paren = (vim_strchr(p, '(') != NULL);
 	if (name == NULL && (fudi.fd_dict == NULL || !paren) && !eap->skip)
 	{
--- a/src/version.c
+++ b/src/version.c
@@ -754,6 +754,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    3705,
+/**/
     3704,
 /**/
     3703,