Patch 9.0.0481
Problem:    In a :def function all closures in a loop get the same variables.
Solution:   Use a separate list of variables for LOADOUTER and STOREOUTER.
            Not copied at end of loop yet.
Files:      src/structs.h, src/vim9.h, src/userfunc.c, src/proto/userfunc.pro,
            src/vim9cmds.c, src/proto/vim9cmds.pro, src/vim9compile.c,
            src/vim9execute.c, src/proto/vim9execute.pro, src/vim9expr.c,
            src/vim9instr.c, src/proto/vim9instr.pro,


*** ../vim-9.0.0480/src/structs.h       2022-09-16 12:10:00.073526252 +0100
--- src/structs.h       2022-09-16 17:12:24.079665221 +0100
***************
*** 1656,1662 ****
  
  /*
   * Structure to hold info for a user function.
!  * When adding a field check copy_func().
   */
  typedef struct
  {
--- 1656,1662 ----
  
  /*
   * Structure to hold info for a user function.
!  * When adding a field check copy_lambda_to_global_func().
   */
  typedef struct
  {
***************
*** 1741,1747 ****
  #define FC_NOARGS   0x200     // no a: variables in lambda
  #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
--- 1741,1748 ----
  #define FC_NOARGS   0x200     // no a: variables in lambda
  #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_lambda_to_global_func()
  #define FC_LAMBDA   0x2000    // one line "return {expr}"
  
  #define MAX_FUNC_ARGS 20      // maximum number of function arguments
***************
*** 2096,2105 ****
  
  typedef struct outer_S outer_T;
  struct outer_S {
!     garray_T  *out_stack;         // stack from outer scope
      int               out_frame_idx;      // index of stack frame in out_stack
      outer_T   *out_up;            // outer scope of outer scope or NULL
      partial_T *out_up_partial;    // partial owning out_up or NULL
  };
  
  struct partial_S
--- 2097,2113 ----
  
  typedef struct outer_S outer_T;
  struct outer_S {
!     garray_T  *out_stack;         // stack from outer scope, or a copy
!                                   // containing only arguments and local vars
      int               out_frame_idx;      // index of stack frame in out_stack
      outer_T   *out_up;            // outer scope of outer scope or NULL
      partial_T *out_up_partial;    // partial owning out_up or NULL
+ 
+     garray_T  *out_loop_stack;    // stack from outer scope, or a copy
+                                   // containing only vars inside the loop
+     short     out_loop_var_idx;   // first variable defined in a loop
+                                   // in out_loop_stack
+     short     out_loop_var_count; // number of variables defined in a loop
  };
  
  struct partial_S
*** ../vim-9.0.0480/src/vim9.h  2022-09-15 17:19:30.022390551 +0100
--- src/vim9.h  2022-09-16 17:39:50.823126806 +0100
***************
*** 354,369 ****
      int               ul_forceit;     // forceit flag
  } unlet_T;
  
  // 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
  typedef struct {
!     char_u    *nf_lambda;     // name of the lambda already defined
!     char_u    *nf_global;     // name of the global function to be created
  } newfunc_T;
  
  // arguments to ISN_CHECKLEN
--- 354,382 ----
      int               ul_forceit;     // forceit flag
  } unlet_T;
  
+ // extra arguments for funcref_T
+ typedef struct {
+     char_u    *fre_func_name;     // function name for legacy function
+     short     fre_loop_var_idx;   // index of first variable inside loop
+     short     fre_loop_var_count; // number of variables inside loop
+ } funcref_extra_T;
+ 
  // arguments to ISN_FUNCREF
  typedef struct {
!     int                   fr_dfunc_idx;   // function index for :def function
!     funcref_extra_T *fr_extra;            // optional extra information
  } funcref_T;
  
  // arguments to ISN_NEWFUNC
  typedef struct {
!     char_u    *nfa_lambda;       // name of the lambda already defined
!     char_u    *nfa_global;       // name of the global function to be created
!     short     nfa_loop_var_idx;    // index of first variable inside loop
!     short     nfa_loop_var_count;  // number of variables inside loop
! } newfuncarg_T;
! 
! typedef struct {
!     newfuncarg_T *nf_arg;
  } newfunc_T;
  
  // arguments to ISN_CHECKLEN
***************
*** 401,406 ****
--- 414,421 ----
      int               outer_depth;    // nesting level, stack frames to go up
  } isn_outer_T;
  
+ #define OUTER_LOOP_DEPTH -9   // used for outer_depth for loop variables
+ 
  // arguments to ISN_SUBSTITUTE
  typedef struct {
      char_u    *subs_cmd;      // :s command
***************
*** 677,682 ****
--- 692,698 ----
      char_u    *lv_name;
      type_T    *lv_type;
      int               lv_idx;         // index of the variable on the stack
+     int               lv_loop_idx;    // index of first variable inside a 
loop or -1
      int               lv_from_outer;  // nesting level, using ctx_outer scope
      int               lv_const;       // when TRUE cannot be assigned to
      int               lv_arg;         // when TRUE this is an argument
*** ../vim-9.0.0480/src/userfunc.c      2022-09-16 12:10:00.073526252 +0100
--- src/userfunc.c      2022-09-16 14:49:10.530297517 +0100
***************
*** 2452,2458 ****
   * This is for when a compiled function defines a global function.
   */
      int
! copy_func(char_u *lambda, char_u *global, ectx_T *ectx)
  {
      ufunc_T *ufunc = find_func_even_dead(lambda, FFED_IS_GLOBAL);
      ufunc_T *fp = NULL;
--- 2452,2463 ----
   * This is for when a compiled function defines a global function.
   */
      int
! copy_lambda_to_global_func(
!       char_u  *lambda,
!       char_u  *global,
!       short   loop_var_idx,
!       short   loop_var_count,
!       ectx_T  *ectx)
  {
      ufunc_T *ufunc = find_func_even_dead(lambda, FFED_IS_GLOBAL);
      ufunc_T *fp = NULL;
***************
*** 2519,2525 ****
  
        if (pt == NULL)
            goto failed;
!       if (fill_partial_and_closure(pt, ufunc, ectx) == FAIL)
        {
            vim_free(pt);
            goto failed;
--- 2524,2531 ----
  
        if (pt == NULL)
            goto failed;
!       if (fill_partial_and_closure(pt, ufunc, loop_var_idx, loop_var_count,
!                                                                ectx) == FAIL)
        {
            vim_free(pt);
            goto failed;
*** ../vim-9.0.0480/src/proto/userfunc.pro      2022-09-07 21:30:40.143379043 
+0100
--- src/proto/userfunc.pro      2022-09-16 14:59:41.808573778 +0100
***************
*** 16,22 ****
  int func_requires_g_prefix(ufunc_T *ufunc);
  int func_name_refcount(char_u *name);
  void func_clear_free(ufunc_T *fp, int force);
! int copy_func(char_u *lambda, char_u *global, ectx_T *ectx);
  int funcdepth_increment(void);
  void funcdepth_decrement(void);
  int funcdepth_get(void);
--- 16,22 ----
  int func_requires_g_prefix(ufunc_T *ufunc);
  int func_name_refcount(char_u *name);
  void func_clear_free(ufunc_T *fp, int force);
! int copy_lambda_to_global_func(char_u *lambda, char_u *global, short 
loop_var_idx, short loop_var_count, ectx_T *ectx);
  int funcdepth_increment(void);
  void funcdepth_decrement(void);
  int funcdepth_get(void);
*** ../vim-9.0.0480/src/vim9cmds.c      2022-09-15 17:19:30.022390551 +0100
--- src/vim9cmds.c      2022-09-16 17:42:19.746693534 +0100
***************
*** 1246,1251 ****
--- 1246,1294 ----
  }
  
  /*
+  * Get the current information about variables declared inside a loop.
+  * Returns zero if there are none, otherwise the count.
+  * "loop_var_idx" is then set to the index of the first variable.
+  */
+     short
+ get_loop_var_info(cctx_T *cctx, short *loop_var_idx)
+ {
+     scope_T   *scope = cctx->ctx_scope;
+     int               start_local_count;
+ 
+     while (scope != NULL && scope->se_type != WHILE_SCOPE
+                                               && scope->se_type != FOR_SCOPE)
+       scope = scope->se_outer;
+     if (scope == NULL)
+       return 0;
+ 
+     if (scope->se_type == WHILE_SCOPE)
+       start_local_count = scope->se_u.se_while.ws_local_count;
+     else
+       start_local_count = scope->se_u.se_for.fs_local_count;
+     if (cctx->ctx_locals.ga_len > start_local_count)
+     {
+       *loop_var_idx = (short)start_local_count;
+       return (short)(cctx->ctx_locals.ga_len - start_local_count);
+     }
+     return 0;
+ }
+ 
+ /*
+  * Get the index of the first variable in a loop, if any.
+  * Returns -1 if none.
+  */
+     int
+ get_loop_var_idx(cctx_T *cctx)
+ {
+     short loop_var_idx;
+ 
+     if (get_loop_var_info(cctx, &loop_var_idx) > 0)
+       return loop_var_idx;
+     return -1;
+ }
+ 
+ /*
   * compile "continue"
   */
      char_u *
*** ../vim-9.0.0480/src/proto/vim9cmds.pro      2022-09-04 15:40:31.816188110 
+0100
--- src/proto/vim9cmds.pro      2022-09-16 17:43:16.122532065 +0100
***************
*** 11,16 ****
--- 11,18 ----
  char_u *compile_endfor(char_u *arg, cctx_T *cctx);
  char_u *compile_while(char_u *arg, cctx_T *cctx);
  char_u *compile_endwhile(char_u *arg, cctx_T *cctx);
+ short get_loop_var_info(cctx_T *cctx, short *loop_var_idx);
+ int get_loop_var_idx(cctx_T *cctx);
  char_u *compile_continue(char_u *arg, cctx_T *cctx);
  char_u *compile_break(char_u *arg, cctx_T *cctx);
  char_u *compile_block(char_u *arg, cctx_T *cctx);
*** ../vim-9.0.0480/src/vim9compile.c   2022-09-15 17:19:30.026390537 +0100
--- src/vim9compile.c   2022-09-16 17:50:06.701384676 +0100
***************
*** 54,59 ****
--- 54,60 ----
            {
                *lvar = *lvp;
                lvar->lv_from_outer = 0;
+               lvar->lv_loop_idx = get_loop_var_idx(cctx);
            }
            return OK;
        }
***************
*** 954,960 ****
      // recursive call.
      if (is_global)
      {
!       r = generate_NEWFUNC(cctx, lambda_name, func_name);
        func_name = NULL;
        lambda_name = NULL;
      }
--- 955,962 ----
      // recursive call.
      if (is_global)
      {
!       // TODO: loop variable index and count
!       r = generate_NEWFUNC(cctx, lambda_name, func_name, 0, 0);
        func_name = NULL;
        lambda_name = NULL;
      }
***************
*** 1193,1199 ****
            {
                if (lvar->lv_from_outer > 0)
                    generate_LOADOUTER(cctx, lvar->lv_idx, lvar->lv_from_outer,
!                                                                        type);
                else
                    generate_LOAD(cctx, ISN_LOAD, lvar->lv_idx, NULL, type);
            }
--- 1195,1201 ----
            {
                if (lvar->lv_from_outer > 0)
                    generate_LOADOUTER(cctx, lvar->lv_idx, lvar->lv_from_outer,
!                                                     lvar->lv_loop_idx, type);
                else
                    generate_LOAD(cctx, ISN_LOAD, lvar->lv_idx, NULL, type);
            }
*** ../vim-9.0.0480/src/vim9execute.c   2022-09-15 17:19:30.026390537 +0100
--- src/vim9execute.c   2022-09-16 18:19:16.005146029 +0100
***************
*** 673,678 ****
--- 673,681 ----
      if (closure_count == 0)
        return OK;  // no funcrefs created
  
+     // Compute "top": the first entry in the stack used by the function.
+     // This is the first argument (after that comes the stack frame and then
+     // the local variables).
      argcount = ufunc_argcount(dfunc->df_ufunc);
      top = ectx->ec_frame_idx - argcount;
  
***************
*** 740,745 ****
--- 743,749 ----
            else
                copy_tv(tv, stack + idx);
        }
+       // Skip the stack frame.
        // Move the local variables.
        for (idx = 0; idx < dfunc->df_varcount; ++idx)
        {
***************
*** 770,779 ****
--- 774,790 ----
                                                        - closure_count + idx];
            if (pt->pt_refcount > 1)
            {
+               int     prev_frame_idx = pt->pt_outer.out_frame_idx;
+ 
                ++funcstack->fs_refcount;
                pt->pt_funcstack = funcstack;
                pt->pt_outer.out_stack = &funcstack->fs_ga;
                pt->pt_outer.out_frame_idx = ectx->ec_frame_idx - top;
+ 
+               // TODO: drop this, should be done at ISN_ENDLOOP
+               pt->pt_outer.out_loop_stack = &funcstack->fs_ga;
+               pt->pt_outer.out_loop_var_idx -=
+                                  prev_frame_idx - pt->pt_outer.out_frame_idx;
            }
        }
      }
***************
*** 1814,1820 ****
   * needed, especially when it is used as a closure.
   */
      int
! fill_partial_and_closure(partial_T *pt, ufunc_T *ufunc, ectx_T *ectx)
  {
      pt->pt_func = ufunc;
      pt->pt_refcount = 1;
--- 1825,1836 ----
   * needed, especially when it is used as a closure.
   */
      int
! fill_partial_and_closure(
!       partial_T   *pt,
!       ufunc_T     *ufunc,
!       short       loop_var_idx,
!       short       loop_var_count,
!       ectx_T      *ectx)
  {
      pt->pt_func = ufunc;
      pt->pt_refcount = 1;
***************
*** 1839,1844 ****
--- 1855,1868 ----
            }
        }
  
+       // The closure may need to find variables defined inside a loop.  A
+       // new reference is made every time, ISN_ENDLOOP will check if they
+       // are actually used.
+       pt->pt_outer.out_loop_stack = &ectx->ec_stack;
+       pt->pt_outer.out_loop_var_idx = ectx->ec_frame_idx + STACK_FRAME_SIZE
+                                                               + loop_var_idx;
+       pt->pt_outer.out_loop_var_count = loop_var_count;
+ 
        // If the function currently executing returns and the closure is still
        // being referenced, we need to make a copy of the context (arguments
        // and local variables) so that the closure can use it later.
***************
*** 1853,1860 ****
        ++(((typval_T *)ectx->ec_stack.ga_data) + ectx->ec_frame_idx
                       + STACK_FRAME_SIZE + dfunc->df_varcount)->vval.v_number;
  
!       ((partial_T **)ectx->ec_funcrefs.ga_data)
!                              [ectx->ec_funcrefs.ga_len] = pt;
        ++pt->pt_refcount;
        ++ectx->ec_funcrefs.ga_len;
      }
--- 1877,1884 ----
        ++(((typval_T *)ectx->ec_stack.ga_data) + ectx->ec_frame_idx
                       + STACK_FRAME_SIZE + dfunc->df_varcount)->vval.v_number;
  
!       ((partial_T **)ectx->ec_funcrefs.ga_data)[ectx->ec_funcrefs.ga_len]
!                                                                         = pt;
        ++pt->pt_refcount;
        ++ectx->ec_funcrefs.ga_len;
      }
***************
*** 3610,3618 ****
                            iemsg("LOADOUTER depth more than scope levels");
                        goto theend;
                    }
!                   tv = ((typval_T *)outer->out_stack->ga_data)
!                                   + outer->out_frame_idx + STACK_FRAME_SIZE
!                                   + iptr->isn_arg.outer.outer_idx;
                    if (iptr->isn_type == ISN_LOADOUTER)
                    {
                        if (GA_GROW_FAILS(&ectx->ec_stack, 1))
--- 3634,3648 ----
                            iemsg("LOADOUTER depth more than scope levels");
                        goto theend;
                    }
!                   if (depth == OUTER_LOOP_DEPTH)
!                       // variable declared in loop
!                       tv = ((typval_T *)outer->out_loop_stack->ga_data)
!                                           + outer->out_loop_var_idx
!                                           + iptr->isn_arg.outer.outer_idx;
!                   else
!                       tv = ((typval_T *)outer->out_stack->ga_data)
!                                     + outer->out_frame_idx + STACK_FRAME_SIZE
!                                     + iptr->isn_arg.outer.outer_idx;
                    if (iptr->isn_type == ISN_LOADOUTER)
                    {
                        if (GA_GROW_FAILS(&ectx->ec_stack, 1))
***************
*** 3913,3921 ****
            // push a partial, a reference to a compiled function
            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;
--- 3943,3952 ----
            // push a partial, a reference to a compiled function
            case ISN_FUNCREF:
                {
!                   partial_T       *pt = ALLOC_CLEAR_ONE(partial_T);
!                   ufunc_T         *ufunc;
!                   funcref_T       *funcref = &iptr->isn_arg.funcref;
!                   funcref_extra_T *extra = funcref->fr_extra;
  
                    if (pt == NULL)
                        goto theend;
***************
*** 3924,3930 ****
                        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;
--- 3955,3961 ----
                        vim_free(pt);
                        goto theend;
                    }
!                   if (extra == NULL || extra->fre_func_name == NULL)
                    {
                        dfunc_T *pt_dfunc = ((dfunc_T *)def_functions.ga_data)
                                                       + funcref->fr_dfunc_idx;
***************
*** 3932,3947 ****
                        ufunc = pt_dfunc->df_ufunc;
                    }
                    else
!                   {
!                       ufunc = find_func(funcref->fr_func_name, FALSE);
!                   }
                    if (ufunc == NULL)
                    {
                        SOURCING_LNUM = iptr->isn_lnum;
                        iemsg("ufunc unexpectedly NULL for FUNCREF");
                        goto theend;
                    }
!                   if (fill_partial_and_closure(pt, ufunc, ectx) == FAIL)
                        goto theend;
                    tv = STACK_TV_BOT(0);
                    ++ectx->ec_stack.ga_len;
--- 3963,3979 ----
                        ufunc = pt_dfunc->df_ufunc;
                    }
                    else
!                       ufunc = find_func(extra->fre_func_name, FALSE);
                    if (ufunc == NULL)
                    {
                        SOURCING_LNUM = iptr->isn_lnum;
                        iemsg("ufunc unexpectedly NULL for FUNCREF");
                        goto theend;
                    }
!                   if (fill_partial_and_closure(pt, ufunc,
!                               extra == NULL ? 0 : extra->fre_loop_var_idx,
!                               extra == NULL ? 0 : extra->fre_loop_var_count,
!                                                                ectx) == FAIL)
                        goto theend;
                    tv = STACK_TV_BOT(0);
                    ++ectx->ec_stack.ga_len;
***************
*** 3954,3963 ****
            // Create a global function from a lambda.
            case ISN_NEWFUNC:
                {
!                   newfunc_T   *newfunc = &iptr->isn_arg.newfunc;
  
!                   if (copy_func(newfunc->nf_lambda, newfunc->nf_global,
!                                                                ectx) == FAIL)
                        goto theend;
                }
                break;
--- 3986,3996 ----
            // Create a global function from a lambda.
            case ISN_NEWFUNC:
                {
!                   newfuncarg_T    *arg = iptr->isn_arg.newfunc.nf_arg;
  
!                   if (copy_lambda_to_global_func(arg->nfa_lambda,
!                                       arg->nfa_global, arg->nfa_loop_var_idx,
!                                       arg->nfa_loop_var_count, ectx) == FAIL)
                        goto theend;
                }
                break;
***************
*** 5520,5526 ****
        ufunc_T *base_ufunc = dfunc->df_ufunc;
  
        // "uf_partial" is on the ufunc that "df_ufunc" points to, as is done
!       // by copy_func().
        if (partial != NULL || base_ufunc->uf_partial != NULL)
        {
            ectx.ec_outer_ref = ALLOC_CLEAR_ONE(outer_ref_T);
--- 5553,5559 ----
        ufunc_T *base_ufunc = dfunc->df_ufunc;
  
        // "uf_partial" is on the ufunc that "df_ufunc" points to, as is done
!       // by copy_lambda_to_global_func().
        if (partial != NULL || base_ufunc->uf_partial != NULL)
        {
            ectx.ec_outer_ref = ALLOC_CLEAR_ONE(outer_ref_T);
***************
*** 5880,5894 ****
                break;
            case ISN_LOADOUTER:
                {
!                   if (iptr->isn_arg.outer.outer_idx < 0)
                        smsg("%s%4d LOADOUTER level %d arg[%d]", pfx, current,
!                               iptr->isn_arg.outer.outer_depth,
!                               iptr->isn_arg.outer.outer_idx
                                                          + STACK_FRAME_SIZE);
                    else
                        smsg("%s%4d LOADOUTER level %d $%d", pfx, current,
!                                             iptr->isn_arg.outer.outer_depth,
!                                             iptr->isn_arg.outer.outer_idx);
                }
                break;
            case ISN_LOADV:
--- 5913,5932 ----
                break;
            case ISN_LOADOUTER:
                {
!                   isn_outer_T *outer = &iptr->isn_arg.outer;
! 
!                   if (outer->outer_idx < 0)
                        smsg("%s%4d LOADOUTER level %d arg[%d]", pfx, current,
!                               outer->outer_depth,
!                               outer->outer_idx
                                                          + STACK_FRAME_SIZE);
+                   else if (outer->outer_depth == OUTER_LOOP_DEPTH)
+                       smsg("%s%4d LOADOUTER level 1 $%d in loop",
+                                              pfx, current, outer->outer_idx);
                    else
                        smsg("%s%4d LOADOUTER level %d $%d", pfx, current,
!                                             outer->outer_depth,
!                                             outer->outer_idx);
                }
                break;
            case ISN_LOADV:
***************
*** 5971,5979 ****
                                                         iptr->isn_arg.number);
                break;
            case ISN_STOREOUTER:
!               smsg("%s%4d STOREOUTER level %d $%d", pfx, current,
!                       iptr->isn_arg.outer.outer_depth,
!                       iptr->isn_arg.outer.outer_idx);
                break;
            case ISN_STOREV:
                smsg("%s%4d STOREV v:%s", pfx, current,
--- 6009,6024 ----
                                                         iptr->isn_arg.number);
                break;
            case ISN_STOREOUTER:
!               {
!                   isn_outer_T *outer = &iptr->isn_arg.outer;
! 
!                   if (outer->outer_depth == OUTER_LOOP_DEPTH)
!                       smsg("%s%4d STOREOUTER level 1 $%d in loop",
!                               pfx, current, outer->outer_idx);
!                   else
!                       smsg("%s%4d STOREOUTER level %d $%d", pfx, current,
!                               outer->outer_depth, outer->outer_idx);
!               }
                break;
            case ISN_STOREV:
                smsg("%s%4d STOREV v:%s", pfx, current,
***************
*** 6190,6216 ****
                break;
            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;
  
            case ISN_NEWFUNC:
                {
!                   newfunc_T   *newfunc = &iptr->isn_arg.newfunc;
  
!                   smsg("%s%4d NEWFUNC %s %s", pfx, current,
!                                      newfunc->nf_lambda, newfunc->nf_global);
                }
                break;
  
--- 6235,6275 ----
                break;
            case ISN_FUNCREF:
                {
!                   funcref_T           *funcref = &iptr->isn_arg.funcref;
!                   funcref_extra_T     *extra = funcref->fr_extra;
!                   char_u              *name;
  
!                   if (extra == NULL || extra->fre_func_name == NULL)
                    {
                        dfunc_T *df = ((dfunc_T *)def_functions.ga_data)
                                                       + funcref->fr_dfunc_idx;
                        name = df->df_ufunc->uf_name;
                    }
                    else
!                       name = extra->fre_func_name;
!                   if (extra == NULL || extra->fre_loop_var_count == 0)
!                       smsg("%s%4d FUNCREF %s", pfx, current, name);
!                   else
!                       smsg("%s%4d FUNCREF %s var $%d - $%d", pfx, current,
!                               name,
!                               extra->fre_loop_var_idx,
!                               extra->fre_loop_var_idx
!                                             + extra->fre_loop_var_count - 1);
                }
                break;
  
            case ISN_NEWFUNC:
                {
!                   newfuncarg_T        *arg = iptr->isn_arg.newfunc.nf_arg;
  
!                   if (arg->nfa_loop_var_count == 0)
!                       smsg("%s%4d NEWFUNC %s %s", pfx, current,
!                                            arg->nfa_lambda, arg->nfa_global);
!                   else
!                       smsg("%s%4d NEWFUNC %s %s var $%d - $%d", pfx, current,
!                         arg->nfa_lambda, arg->nfa_global,
!                         arg->nfa_loop_var_idx,
!                         arg->nfa_loop_var_idx + arg->nfa_loop_var_count - 1);
                }
                break;
  
*** ../vim-9.0.0480/src/proto/vim9execute.pro   2022-09-07 16:48:41.183678514 
+0100
--- src/proto/vim9execute.pro   2022-09-16 14:38:42.748130110 +0100
***************
*** 9,15 ****
  int add_defer_function(char_u *name, int argcount, typval_T *argvars);
  char_u *char_from_string(char_u *str, varnumber_T index);
  char_u *string_slice(char_u *str, varnumber_T first, varnumber_T last, int 
exclusive);
! int fill_partial_and_closure(partial_T *pt, ufunc_T *ufunc, ectx_T *ectx);
  int may_load_script(int sid, int *loaded);
  typval_T *lookup_debug_var(char_u *name);
  int may_break_in_function(ufunc_T *ufunc);
--- 9,15 ----
  int add_defer_function(char_u *name, int argcount, typval_T *argvars);
  char_u *char_from_string(char_u *str, varnumber_T index);
  char_u *string_slice(char_u *str, varnumber_T first, varnumber_T last, int 
exclusive);
! int fill_partial_and_closure(partial_T *pt, ufunc_T *ufunc, short 
loop_var_idx, short loop_var_count, ectx_T *ectx);
  int may_load_script(int sid, int *loaded);
  typval_T *lookup_debug_var(char_u *name);
  int may_break_in_function(ufunc_T *ufunc);
*** ../vim-9.0.0480/src/vim9expr.c      2022-09-11 11:49:19.098228660 +0100
--- src/vim9expr.c      2022-09-16 17:48:36.265634058 +0100
***************
*** 496,501 ****
--- 496,502 ----
        int         idx;
        int         gen_load = FALSE;
        int         gen_load_outer = 0;
+       int         outer_loop_idx = -1;
  
        name = vim_strnsave(*arg, end - *arg);
        if (name == NULL)
***************
*** 520,525 ****
--- 521,527 ----
            {
                type = lvar.lv_type;
                idx = lvar.lv_idx;
+               outer_loop_idx = lvar.lv_loop_idx;
                if (lvar.lv_from_outer != 0)
                    gen_load_outer = lvar.lv_from_outer;
                else
***************
*** 544,550 ****
            res = generate_LOAD(cctx, ISN_LOAD, idx, NULL, type);
        if (gen_load_outer > 0)
        {
!           res = generate_LOADOUTER(cctx, idx, gen_load_outer, type);
            cctx->ctx_outer_used = TRUE;
        }
      }
--- 546,553 ----
            res = generate_LOAD(cctx, ISN_LOAD, idx, NULL, type);
        if (gen_load_outer > 0)
        {
!           res = generate_LOADOUTER(cctx, idx,
!                                        gen_load_outer, outer_loop_idx, type);
            cctx->ctx_outer_used = TRUE;
        }
      }
*** ../vim-9.0.0480/src/vim9instr.c     2022-09-15 17:19:30.026390537 +0100
--- src/vim9instr.c     2022-09-16 18:52:31.835791137 +0100
***************
*** 916,930 ****
   * Generate an ISN_STOREOUTER instruction.
   */
      static int
! generate_STOREOUTER(cctx_T *cctx, int idx, int level)
  {
      isn_T     *isn;
  
      RETURN_OK_IF_SKIP(cctx);
      if ((isn = generate_instr_drop(cctx, ISN_STOREOUTER, 1)) == NULL)
        return FAIL;
!     isn->isn_arg.outer.outer_idx = idx;
!     isn->isn_arg.outer.outer_depth = level;
  
      return OK;
  }
--- 916,940 ----
   * Generate an ISN_STOREOUTER instruction.
   */
      static int
! generate_STOREOUTER(cctx_T *cctx, int idx, int level, int loop_idx)
  {
      isn_T     *isn;
  
      RETURN_OK_IF_SKIP(cctx);
      if ((isn = generate_instr_drop(cctx, ISN_STOREOUTER, 1)) == NULL)
        return FAIL;
!     if (level == 1 && loop_idx >= 0 && idx >= loop_idx)
!     {
!       // Store a variable defined in a loop.  A copy will be made at the end
!       // of the loop.  TODO: how about deeper nesting?
!       isn->isn_arg.outer.outer_idx = idx - loop_idx;
!       isn->isn_arg.outer.outer_depth = OUTER_LOOP_DEPTH;
!     }
!     else
!     {
!       isn->isn_arg.outer.outer_idx = idx;
!       isn->isn_arg.outer.outer_depth = level;
!     }
  
      return OK;
  }
***************
*** 999,1004 ****
--- 1009,1015 ----
        cctx_T      *cctx,
        int         idx,
        int         nesting,
+       int         loop_idx,
        type_T      *type)
  {
      isn_T     *isn;
***************
*** 1006,1013 ****
      RETURN_OK_IF_SKIP(cctx);
      if ((isn = generate_instr_type2(cctx, ISN_LOADOUTER, type, type)) == NULL)
        return FAIL;
!     isn->isn_arg.outer.outer_idx = idx;
!     isn->isn_arg.outer.outer_depth = nesting;
  
      return OK;
  }
--- 1017,1034 ----
      RETURN_OK_IF_SKIP(cctx);
      if ((isn = generate_instr_type2(cctx, ISN_LOADOUTER, type, type)) == NULL)
        return FAIL;
!     if (nesting == 1 && loop_idx >= 0 && idx >= loop_idx)
!     {
!       // Load a variable defined in a loop.  A copy will be made at the end
!       // of the loop.  TODO: how about deeper nesting?
!       isn->isn_arg.outer.outer_idx = idx - loop_idx;
!       isn->isn_arg.outer.outer_depth = OUTER_LOOP_DEPTH;
!     }
!     else
!     {
!       isn->isn_arg.outer.outer_idx = idx;
!       isn->isn_arg.outer.outer_depth = nesting;
!     }
  
      return OK;
  }
***************
*** 1186,1205 ****
  /*
   * Generate an ISN_FUNCREF instruction.
   * "isnp" is set to the instruction, so that fr_dfunc_idx can be set later.
   */
      int
! generate_FUNCREF(cctx_T *cctx, ufunc_T *ufunc, isn_T **isnp)
  {
!     isn_T     *isn;
!     type_T    *type;
  
      RETURN_OK_IF_SKIP(cctx);
      if ((isn = generate_instr(cctx, ISN_FUNCREF)) == NULL)
        return FAIL;
      if (isnp != NULL)
        *isnp = isn;
      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;
--- 1207,1245 ----
  /*
   * Generate an ISN_FUNCREF instruction.
   * "isnp" is set to the instruction, so that fr_dfunc_idx can be set later.
+  * If variables were declared inside a loop "loop_var_idx" is the index of the
+  * first one and "loop_var_count" the number of variables declared.
   */
      int
! generate_FUNCREF(
!       cctx_T      *cctx,
!       ufunc_T     *ufunc,
!       isn_T       **isnp)
  {
!     isn_T         *isn;
!     type_T        *type;
!     funcref_extra_T *extra;
!     short         loop_var_idx;
!     short         loop_var_count;
  
      RETURN_OK_IF_SKIP(cctx);
      if ((isn = generate_instr(cctx, ISN_FUNCREF)) == NULL)
        return FAIL;
      if (isnp != NULL)
        *isnp = isn;
+ 
+     loop_var_count = get_loop_var_info(cctx, &loop_var_idx);
+     if (ufunc->uf_def_status == UF_NOT_COMPILED || loop_var_count > 0)
+     {
+       extra = ALLOC_CLEAR_ONE(funcref_extra_T);
+       if (extra == NULL)
+           return FAIL;
+       isn->isn_arg.funcref.fr_extra = extra;
+       extra->fre_loop_var_idx = loop_var_idx;
+       extra->fre_loop_var_count = loop_var_count;
+     }
      if (ufunc->uf_def_status == UF_NOT_COMPILED)
!       extra->fre_func_name = vim_strsave(ufunc->uf_name);
      else
        isn->isn_arg.funcref.fr_dfunc_idx = ufunc->uf_dfunc_idx;
      cctx->ctx_has_closure = 1;
***************
*** 1221,1227 ****
   * consumed.
   */
      int
! generate_NEWFUNC(cctx_T *cctx, char_u *lambda_name, char_u *func_name)
  {
      isn_T     *isn;
      int               ret = OK;
--- 1261,1272 ----
   * consumed.
   */
      int
! generate_NEWFUNC(
!       cctx_T  *cctx,
!       char_u  *lambda_name,
!       char_u  *func_name,
!       short   loop_var_idx,
!       short   loop_var_count)
  {
      isn_T     *isn;
      int               ret = OK;
***************
*** 1232,1240 ****
            ret = FAIL;
        else
        {
!           isn->isn_arg.newfunc.nf_lambda = lambda_name;
!           isn->isn_arg.newfunc.nf_global = func_name;
!           return OK;
        }
      }
      vim_free(lambda_name);
--- 1277,1295 ----
            ret = FAIL;
        else
        {
!           newfuncarg_T *arg = ALLOC_CLEAR_ONE(newfuncarg_T);
! 
!           if (arg == NULL)
!               ret = FAIL;
!           else
!           {
!               isn->isn_arg.newfunc.nf_arg = arg;
!               arg->nfa_lambda = lambda_name;
!               arg->nfa_global = func_name;
!               arg->nfa_loop_var_idx = loop_var_idx;
!               arg->nfa_loop_var_count = loop_var_count;
!               return OK;
!           }
        }
      }
      vim_free(lambda_name);
***************
*** 2123,2129 ****
        }
        else if (lhs->lhs_lvar->lv_from_outer > 0)
            generate_STOREOUTER(cctx, lhs->lhs_lvar->lv_idx,
!                                                lhs->lhs_lvar->lv_from_outer);
        else
            generate_STORE(cctx, ISN_STORE, lhs->lhs_lvar->lv_idx, NULL);
      }
--- 2178,2184 ----
        }
        else if (lhs->lhs_lvar->lv_from_outer > 0)
            generate_STOREOUTER(cctx, lhs->lhs_lvar->lv_idx,
!                    lhs->lhs_lvar->lv_from_outer, lhs->lhs_lvar->lv_loop_idx);
        else
            generate_STORE(cctx, ISN_STORE, lhs->lhs_lvar->lv_idx, NULL);
      }
***************
*** 2226,2247 ****
  
        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;
--- 2281,2308 ----
  
        case ISN_FUNCREF:
            {
!               funcref_T       *funcref = &isn->isn_arg.funcref;
!               funcref_extra_T *extra = funcref->fr_extra;
! 
!               if (extra == NULL || extra->fre_func_name == NULL)
                {
                    dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
!                                                      + funcref->fr_dfunc_idx;
                    ufunc_T *ufunc = dfunc->df_ufunc;
  
                    if (ufunc != NULL && func_name_refcount(ufunc->uf_name))
                        func_ptr_unref(ufunc);
                }
!               if (extra != NULL)
                {
!                   char_u *name = extra->fre_func_name;
  
                    if (name != NULL)
+                   {
                        func_unref(name);
!                       vim_free(name);
!                   }
!                   vim_free(extra);
                }
            }
            break;
***************
*** 2259,2275 ****
  
        case ISN_NEWFUNC:
            {
!               char_u  *lambda = isn->isn_arg.newfunc.nf_lambda;
!               ufunc_T *ufunc = find_func_even_dead(lambda, FFED_IS_GLOBAL);
  
!               if (ufunc != NULL)
                {
!                   unlink_def_function(ufunc);
!                   func_ptr_unref(ufunc);
!               }
  
!               vim_free(lambda);
!               vim_free(isn->isn_arg.newfunc.nf_global);
            }
            break;
  
--- 2320,2342 ----
  
        case ISN_NEWFUNC:
            {
!               newfuncarg_T *arg = isn->isn_arg.newfunc.nf_arg;
  
!               if (arg != NULL)
                {
!                   ufunc_T *ufunc = find_func_even_dead(
!                                             arg->nfa_lambda, FFED_IS_GLOBAL);
  
!                   if (ufunc != NULL)
!                   {
!                       unlink_def_function(ufunc);
!                       func_ptr_unref(ufunc);
!                   }
! 
!                   vim_free(arg->nfa_lambda);
!                   vim_free(arg->nfa_global);
!                   vim_free(arg);
!               }
            }
            break;
  
*** ../vim-9.0.0480/src/proto/vim9instr.pro     2022-09-15 17:19:30.026390537 
+0100
--- src/proto/vim9instr.pro     2022-09-16 17:51:45.897112726 +0100
***************
*** 31,37 ****
  int generate_STORE(cctx_T *cctx, isntype_T isn_type, int idx, char_u *name);
  int generate_STORENR(cctx_T *cctx, int idx, varnumber_T value);
  int generate_LOAD(cctx_T *cctx, isntype_T isn_type, int idx, char_u *name, 
type_T *type);
! int generate_LOADOUTER(cctx_T *cctx, int idx, int nesting, type_T *type);
  int generate_LOADV(cctx_T *cctx, char_u *name);
  int generate_UNLET(cctx_T *cctx, isntype_T isn_type, char_u *name, int 
forceit);
  int generate_LOCKCONST(cctx_T *cctx);
--- 31,37 ----
  int generate_STORE(cctx_T *cctx, isntype_T isn_type, int idx, char_u *name);
  int generate_STORENR(cctx_T *cctx, int idx, varnumber_T value);
  int generate_LOAD(cctx_T *cctx, isntype_T isn_type, int idx, char_u *name, 
type_T *type);
! int generate_LOADOUTER(cctx_T *cctx, int idx, int nesting, int loop_idx, 
type_T *type);
  int generate_LOADV(cctx_T *cctx, char_u *name);
  int generate_UNLET(cctx_T *cctx, isntype_T isn_type, char_u *name, int 
forceit);
  int generate_LOCKCONST(cctx_T *cctx);
***************
*** 40,46 ****
  int generate_NEWLIST(cctx_T *cctx, int count, int use_null);
  int generate_NEWDICT(cctx_T *cctx, int count, int use_null);
  int generate_FUNCREF(cctx_T *cctx, ufunc_T *ufunc, isn_T **isnp);
! int generate_NEWFUNC(cctx_T *cctx, char_u *lambda_name, char_u *func_name);
  int generate_DEF(cctx_T *cctx, char_u *name, size_t len);
  int generate_JUMP(cctx_T *cctx, jumpwhen_T when, int where);
  int generate_WHILE(cctx_T *cctx, int funcref_idx);
--- 40,46 ----
  int generate_NEWLIST(cctx_T *cctx, int count, int use_null);
  int generate_NEWDICT(cctx_T *cctx, int count, int use_null);
  int generate_FUNCREF(cctx_T *cctx, ufunc_T *ufunc, isn_T **isnp);
! int generate_NEWFUNC(cctx_T *cctx, char_u *lambda_name, char_u *func_name, 
short loop_var_idx, short loop_var_count);
  int generate_DEF(cctx_T *cctx, char_u *name, size_t len);
  int generate_JUMP(cctx_T *cctx, jumpwhen_T when, int where);
  int generate_WHILE(cctx_T *cctx, int funcref_idx);
*** ../vim-9.0.0480/src/version.c       2022-09-16 16:06:29.066260406 +0100
--- src/version.c       2022-09-16 19:02:02.158253404 +0100
***************
*** 705,706 ****
--- 705,708 ----
  {   /* Add new patch number below this line */
+ /**/
+     481,
  /**/

-- 
The sooner you fall behind, the more time you'll have to catch up.

 /// 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/20220916180451.970211C0846%40moolenaar.net.

Raspunde prin e-mail lui