Patch 8.2.3692
Problem:    Vim9: cannot use :func inside a :def function.
Solution:   Make it work.
Files:      src/vim9compile.c, src/vim9.h, src/vim9execute.c, src/errors.h,
            src/structs.h, src/userfunc.c, src/testdir/test_vim9_func.vim


*** ../vim-8.2.3691/src/vim9compile.c   2021-11-23 12:35:54.350064548 +0000
--- src/vim9compile.c   2021-11-28 21:54:52.784775660 +0000
***************
*** 1675,1681 ****
      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;
      cctx->ctx_has_closure = 1;
  
      // If the referenced function is a closure, it may use items further up in
--- 1675,1684 ----
      RETURN_OK_IF_SKIP(cctx);
      if ((isn = generate_instr(cctx, ISN_FUNCREF)) == NULL)
        return FAIL;
!     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,5840 ****
--- 5838,5844 ----
      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,9991 ****
        switch (ea.cmdidx)
        {
            case CMD_def:
                    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);
--- 9980,9990 ----
        switch (ea.cmdidx)
        {
            case CMD_def:
+           case CMD_function:
                    ea.arg = p;
                    line = compile_nested_function(&ea, &cctx);
                    break;
  
            case CMD_return:
                    line = compile_return(p, check_return_type,
                                 local_cmdmod.cmod_flags & CMOD_LEGACY, &cctx);
***************
*** 10442,10453 ****
  
        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 (ufunc != NULL && func_name_refcount(ufunc->uf_name))
!                   func_ptr_unref(ufunc);
            }
            break;
  
--- 10441,10463 ----
  
        case ISN_FUNCREF:
            {
!               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);
!               }
!               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;
  
*** ../vim-8.2.3691/src/vim9.h  2021-09-16 15:15:00.204224417 +0100
--- src/vim9.h  2021-11-28 21:01:31.606756591 +0000
***************
*** 322,328 ****
  
  // arguments to ISN_FUNCREF
  typedef struct {
!     int               fr_func;        // function index
  } funcref_T;
  
  // arguments to ISN_NEWFUNC
--- 322,329 ----
  
  // arguments to ISN_FUNCREF
  typedef struct {
!     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
*** ../vim-8.2.3691/src/vim9execute.c   2021-11-23 22:16:30.522773542 +0000
--- src/vim9execute.c   2021-11-28 21:16:49.706158909 +0000
***************
*** 3168,3175 ****
            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;
  
                    if (pt == NULL)
                        goto theend;
--- 3168,3175 ----
            case ISN_FUNCREF:
                {
                    partial_T   *pt = ALLOC_CLEAR_ONE(partial_T);
!                   ufunc_T     *ufunc;
!                   funcref_T   *funcref = &iptr->isn_arg.funcref;
  
                    if (pt == NULL)
                        goto theend;
***************
*** 3178,3185 ****
                        vim_free(pt);
                        goto theend;
                    }
!                   if (fill_partial_and_closure(pt, pt_dfunc->df_ufunc,
!                                                                ectx) == FAIL)
                        goto theend;
                    tv = STACK_TV_BOT(0);
                    ++ectx->ec_stack.ga_len;
--- 3178,3195 ----
                        vim_free(pt);
                        goto theend;
                    }
!                   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,5463 ****
            case ISN_FUNCREF:
                {
                    funcref_T   *funcref = &iptr->isn_arg.funcref;
!                   dfunc_T     *df = ((dfunc_T *)def_functions.ga_data)
!                                                           + funcref->fr_func;
  
!                   smsg("%s%4d FUNCREF %s", pfx, current, 
df->df_ufunc->uf_name);
                }
                break;
  
--- 5464,5480 ----
            case ISN_FUNCREF:
                {
                    funcref_T   *funcref = &iptr->isn_arg.funcref;
!                   char_u      *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;
  
*** ../vim-8.2.3691/src/errors.h        2021-11-24 12:17:49.168449919 +0000
--- src/errors.h        2021-11-28 21:54:43.836795171 +0000
***************
*** 355,362 ****
        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"));
  EXTERN char e_cannot_use_index_when_declaring_variable[]
        INIT(= N_("E1087: Cannot use an index when declaring a variable"));
  // E1088 unused
--- 355,361 ----
        INIT(= N_("E1084: Cannot delete Vim9 script function %s"));
  EXTERN char e_not_callable_type_str[]
        INIT(= N_("E1085: Not a callable type: %s"));
! // E1086 unused
  EXTERN char e_cannot_use_index_when_declaring_variable[]
        INIT(= N_("E1087: Cannot use an index when declaring a variable"));
  // E1088 unused
*** ../vim-8.2.3691/src/structs.h       2021-11-24 16:32:50.720422469 +0000
--- src/structs.h       2021-11-28 21:44:06.182134663 +0000
***************
*** 1699,1704 ****
--- 1699,1705 ----
  #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
*** ../vim-8.2.3691/src/userfunc.c      2021-11-20 21:46:16.088614817 +0000
--- src/userfunc.c      2021-11-28 21:47:12.133757952 +0000
***************
*** 523,529 ****
      fp->uf_def_status = UF_NOT_COMPILED;
      fp->uf_refcount = 1;
      fp->uf_varargs = TRUE;
!     fp->uf_flags = FC_CFUNC;
      fp->uf_calls = 0;
      fp->uf_script_ctx = current_sctx;
      fp->uf_cb = cb;
--- 523,529 ----
      fp->uf_def_status = UF_NOT_COMPILED;
      fp->uf_refcount = 1;
      fp->uf_varargs = TRUE;
!     fp->uf_flags = FC_CFUNC | FC_LAMBDA;
      fp->uf_calls = 0;
      fp->uf_script_ctx = current_sctx;
      fp->uf_cb = cb;
***************
*** 1205,1210 ****
--- 1205,1211 ----
      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,1405 ****
      if (evaluate)
      {
        int         len;
!       int         flags = 0;
        char_u      *p;
        char_u      *line_end;
        char_u      *name = get_lambda_name();
--- 1400,1406 ----
      if (evaluate)
      {
        int         len;
!       int         flags = FC_LAMBDA;
        char_u      *p;
        char_u      *line_end;
        char_u      *name = get_lambda_name();
***************
*** 2506,2513 ****
        return;
      }
  
!     if (STRNCMP(fp->uf_name, "<lambda>", 8) == 0)
!       islambda = TRUE;
  
      /*
       * Note about using fc->fixvar[]: This is an array of FIXVAR_CNT variables
--- 2507,2513 ----
        return;
      }
  
!     islambda = fp->uf_flags & FC_LAMBDA;
  
      /*
       * Note about using fc->fixvar[]: This is an array of FIXVAR_CNT variables
*** ../vim-8.2.3691/src/testdir/test_vim9_func.vim      2021-11-20 
21:46:16.088614817 +0000
--- src/testdir/test_vim9_func.vim      2021-11-28 21:52:25.885094272 +0000
***************
*** 586,600 ****
  enddef
  
  def Test_nested_function()
!   def Nested(arg: string): string
      return 'nested ' .. arg
    enddef
!   Nested('function')->assert_equal('nested function')
  
    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:')
  
--- 586,604 ----
  enddef
  
  def Test_nested_function()
!   def NestedDef(arg: string): string
      return 'nested ' .. arg
    enddef
!   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(['def s:Nested()', 'enddef'], 'E1075:')
    CheckDefFailure(['def b:Nested()', 'enddef'], 'E1075:')
  
***************
*** 691,696 ****
--- 695,720 ----
        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()
+           func g:Inner()
+             return 'inner'
+           endfunc
+       enddef
+       defcompile
+       Outer()
        g:Inner()->assert_equal('inner')
        delfunc g:Inner
        Outer()
*** ../vim-8.2.3691/src/version.c       2021-11-28 21:33:32.307336723 +0000
--- src/version.c       2021-11-28 21:58:58.072236602 +0000
***************
*** 759,760 ****
--- 759,762 ----
  {   /* Add new patch number below this line */
+ /**/
+     3692,
  /**/

-- 
Wi n0t trei a h0liday in Sweden thi yer?
                 "Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///                                                                      \\\
\\\        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/20211128220040.6A41F1C45E4%40moolenaar.net.

Raspunde prin e-mail lui