]> granicus.if.org Git - vim/commitdiff
patch 8.2.3692: Vim9: cannot use :func inside a :def function v8.2.3692
authorBram Moolenaar <Bram@vim.org>
Sun, 28 Nov 2021 22:00:12 +0000 (22:00 +0000)
committerBram Moolenaar <Bram@vim.org>
Sun, 28 Nov 2021 22:00:12 +0000 (22:00 +0000)
Problem:    Vim9: cannot use :func inside a :def function.
Solution:   Make it work.

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

index 6346bf249a272d394d6b87038e5d1ccb59a3bce0..3c76bb70d5cc2ae16772d96e4e66fc0a8e7027e7 100644 (file)
@@ -355,8 +355,7 @@ EXTERN char e_cannot_delete_vim9_script_function_str[]
        INIT(= N_("E1084: Cannot delete Vim9 script function %s"));
 EXTERN char e_not_callable_type_str[]
        INIT(= N_("E1085: Not a callable type: %s"));
-EXTERN char e_cannot_use_function_inside_def[]
-       INIT(= N_("E1086: Cannot use :function inside :def"));
+// E1086 unused
 EXTERN char e_cannot_use_index_when_declaring_variable[]
        INIT(= N_("E1087: Cannot use an index when declaring a variable"));
 // E1088 unused
index bef7062df96e5e04d175a4d486350681bc9b7618..48a531b86af5f3ff7b9c2a782b9ff15d0a8cd12a 100644 (file)
@@ -1699,6 +1699,7 @@ typedef struct
 #define FC_VIM9            0x400       // defined in vim9 script file
 #define FC_CFUNC    0x800      // defined as Lua C func
 #define FC_COPY            0x1000      // copy of another function by copy_func()
+#define FC_LAMBDA   0x2000     // one line "return {expr}"
 
 #define MAX_FUNC_ARGS  20      // maximum number of function arguments
 #define VAR_SHORT_LEN  20      // short variable name length
index 34f84f251acb564bbc237cacb03adde79abf945d..51b95ab6cf769c63a7462b7824e4fef4f8781bf5 100644 (file)
@@ -586,15 +586,19 @@ def Test_func_with_comments()
 enddef
 
 def Test_nested_function()
-  def Nested(arg: string): string
+  def NestedDef(arg: string): string
     return 'nested ' .. arg
   enddef
-  Nested('function')->assert_equal('nested function')
+  NestedDef(':def')->assert_equal('nested :def')
+
+  func NestedFunc(arg)
+    return 'nested ' .. a:arg
+  endfunc
+  NestedFunc(':func')->assert_equal('nested :func')
 
   CheckDefFailure(['def Nested()', 'enddef', 'Nested(66)'], 'E118:')
   CheckDefFailure(['def Nested(arg: string)', 'enddef', 'Nested()'], 'E119:')
 
-  CheckDefFailure(['func Nested()', 'endfunc'], 'E1086:')
   CheckDefFailure(['def s:Nested()', 'enddef'], 'E1075:')
   CheckDefFailure(['def b:Nested()', 'enddef'], 'E1075:')
 
@@ -702,6 +706,26 @@ def Test_nested_global_function()
   END
   CheckScriptSuccess(lines)
 
+  lines =<< trim END
+      vim9script
+      def Outer()
+          func g:Inner()
+            return 'inner'
+          endfunc
+      enddef
+      defcompile
+      Outer()
+      g:Inner()->assert_equal('inner')
+      delfunc g:Inner
+      Outer()
+      g:Inner()->assert_equal('inner')
+      delfunc g:Inner
+      Outer()
+      g:Inner()->assert_equal('inner')
+      delfunc g:Inner
+  END
+  CheckScriptSuccess(lines)
+
   lines =<< trim END
       vim9script
       def Outer()
index 602d3b79e1e50826e91c55617fb707f5f037b503..c961115e0418b787729b00e010a760f7a7ad801f 100644 (file)
@@ -523,7 +523,7 @@ register_cfunc(cfunc_T cb, cfunc_free_T cb_free, void *state)
     fp->uf_def_status = UF_NOT_COMPILED;
     fp->uf_refcount = 1;
     fp->uf_varargs = TRUE;
-    fp->uf_flags = FC_CFUNC;
+    fp->uf_flags = FC_CFUNC | FC_LAMBDA;
     fp->uf_calls = 0;
     fp->uf_script_ctx = current_sctx;
     fp->uf_cb = cb;
@@ -1205,6 +1205,7 @@ lambda_function_body(
     set_ufunc_name(ufunc, name);
     if (hash_add(&func_hashtab, UF2HIKEY(ufunc)) == FAIL)
        goto erret;
+    ufunc->uf_flags = FC_LAMBDA;
     ufunc->uf_refcount = 1;
     ufunc->uf_args = *newargs;
     newargs->ga_data = NULL;
@@ -1399,7 +1400,7 @@ get_lambda_tv(
     if (evaluate)
     {
        int         len;
-       int         flags = 0;
+       int         flags = FC_LAMBDA;
        char_u      *p;
        char_u      *line_end;
        char_u      *name = get_lambda_name();
@@ -2506,8 +2507,7 @@ call_user_func(
        return;
     }
 
-    if (STRNCMP(fp->uf_name, "<lambda>", 8) == 0)
-       islambda = TRUE;
+    islambda = fp->uf_flags & FC_LAMBDA;
 
     /*
      * Note about using fc->fixvar[]: This is an array of FIXVAR_CNT variables
index e7f2c749c945f13bbb4d8e124ade433415eec9f3..90021bec308184fcb4d844b03a7b602d06eb97c8 100644 (file)
@@ -757,6 +757,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    3692,
 /**/
     3691,
 /**/
index cffa71b381689c5a98457952aa906ed22d0d8e15..88c0469d07d4bda1146f42696769b29e8f5c929a 100644 (file)
@@ -322,7 +322,8 @@ typedef struct {
 
 // arguments to ISN_FUNCREF
 typedef struct {
-    int                fr_func;        // function index
+    int                fr_dfunc_idx;   // function index for :def function
+    char_u     *fr_func_name;  // function name for legacy function
 } funcref_T;
 
 // arguments to ISN_NEWFUNC
index fe692cbec66c1be9103b332e0fffad3e5ace4397..2c4e2030ba4622c0bfeec5aa9795f973ab1a9c0c 100644 (file)
@@ -1675,7 +1675,10 @@ generate_FUNCREF(cctx_T *cctx, ufunc_T *ufunc)
     RETURN_OK_IF_SKIP(cctx);
     if ((isn = generate_instr(cctx, ISN_FUNCREF)) == NULL)
        return FAIL;
-    isn->isn_arg.funcref.fr_func = ufunc->uf_dfunc_idx;
+    if (ufunc->uf_def_status == UF_NOT_COMPILED)
+       isn->isn_arg.funcref.fr_func_name = vim_strsave(ufunc->uf_name);
+    else
+       isn->isn_arg.funcref.fr_dfunc_idx = ufunc->uf_dfunc_idx;
     cctx->ctx_has_closure = 1;
 
     // If the referenced function is a closure, it may use items further up in
@@ -5835,6 +5838,7 @@ compile_nested_function(exarg_T *eap, cctx_T *cctx)
     fill_exarg_from_cctx(eap, cctx);
 
     eap->forceit = FALSE;
+    // We use the special <Lamba>99 name, but it's not really a lambda.
     lambda_name = vim_strsave(get_lambda_name());
     if (lambda_name == NULL)
        return NULL;
@@ -9976,16 +9980,11 @@ compile_def_function(
        switch (ea.cmdidx)
        {
            case CMD_def:
+           case CMD_function:
                    ea.arg = p;
                    line = compile_nested_function(&ea, &cctx);
                    break;
 
-           case CMD_function:
-                   // TODO: should we allow this, e.g. to declare a global
-                   // function?
-                   emsg(_(e_cannot_use_function_inside_def));
-                   goto erret;
-
            case CMD_return:
                    line = compile_return(p, check_return_type,
                                 local_cmdmod.cmod_flags & CMOD_LEGACY, &cctx);
@@ -10442,12 +10441,23 @@ delete_instr(isn_T *isn)
 
        case ISN_FUNCREF:
            {
-               dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
-                                              + isn->isn_arg.funcref.fr_func;
-               ufunc_T *ufunc = dfunc->df_ufunc;
+               if (isn->isn_arg.funcref.fr_func_name == NULL)
+               {
+                   dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
+                                          + isn->isn_arg.funcref.fr_dfunc_idx;
+                   ufunc_T *ufunc = dfunc->df_ufunc;
 
-               if (ufunc != NULL && func_name_refcount(ufunc->uf_name))
-                   func_ptr_unref(ufunc);
+                   if (ufunc != NULL && func_name_refcount(ufunc->uf_name))
+                       func_ptr_unref(ufunc);
+               }
+               else
+               {
+                   char_u *name = isn->isn_arg.funcref.fr_func_name;
+
+                   if (name != NULL)
+                       func_unref(name);
+                   vim_free(isn->isn_arg.funcref.fr_func_name);
+               }
            }
            break;
 
index 5593f582ad1c2b1f691a5e36226df98f1b9af7c7..7704635e9ab44e9563c62fd9294bad432a67d05c 100644 (file)
@@ -3168,8 +3168,8 @@ exec_instructions(ectx_T *ectx)
            case ISN_FUNCREF:
                {
                    partial_T   *pt = ALLOC_CLEAR_ONE(partial_T);
-                   dfunc_T     *pt_dfunc = ((dfunc_T *)def_functions.ga_data)
-                                              + iptr->isn_arg.funcref.fr_func;
+                   ufunc_T     *ufunc;
+                   funcref_T   *funcref = &iptr->isn_arg.funcref;
 
                    if (pt == NULL)
                        goto theend;
@@ -3178,8 +3178,18 @@ exec_instructions(ectx_T *ectx)
                        vim_free(pt);
                        goto theend;
                    }
-                   if (fill_partial_and_closure(pt, pt_dfunc->df_ufunc,
-                                                                ectx) == FAIL)
+                   if (funcref->fr_func_name == NULL)
+                   {
+                       dfunc_T *pt_dfunc = ((dfunc_T *)def_functions.ga_data)
+                                                      + funcref->fr_dfunc_idx;
+
+                       ufunc = pt_dfunc->df_ufunc;
+                   }
+                   else
+                   {
+                       ufunc = find_func(funcref->fr_func_name, FALSE, NULL);
+                   }
+                   if (fill_partial_and_closure(pt, ufunc, ectx) == FAIL)
                        goto theend;
                    tv = STACK_TV_BOT(0);
                    ++ectx->ec_stack.ga_len;
@@ -5454,10 +5464,17 @@ list_instructions(char *pfx, isn_T *instr, int instr_count, ufunc_T *ufunc)
            case ISN_FUNCREF:
                {
                    funcref_T   *funcref = &iptr->isn_arg.funcref;
-                   dfunc_T     *df = ((dfunc_T *)def_functions.ga_data)
-                                                           + funcref->fr_func;
+                   char_u      *name;
 
-                   smsg("%s%4d FUNCREF %s", pfx, current, df->df_ufunc->uf_name);
+                   if (funcref->fr_func_name == NULL)
+                   {
+                       dfunc_T *df = ((dfunc_T *)def_functions.ga_data)
+                                                      + funcref->fr_dfunc_idx;
+                       name = df->df_ufunc->uf_name;
+                   }
+                   else
+                       name = funcref->fr_func_name;
+                   smsg("%s%4d FUNCREF %s", pfx, current, name);
                }
                break;