Patch 8.2.4332
Problem:    Vim9: incomplete test for existing script variable in block.
Solution:   Add a couple more tests.  Fix uncovered problem.
Files:      src/userfunc.c, src/vim9compile.c, src/proto/vim9compile.pro,
            src/vim9script.c, src/vim9expr.c, src/testdir/test_vim9_func.vim


*** ../vim-8.2.4331/src/userfunc.c      2022-02-07 21:53:58.085529486 +0000
--- src/userfunc.c      2022-02-08 20:18:36.215334673 +0000
***************
*** 55,60 ****
--- 55,61 ----
   * If "argtypes" is not NULL also get the type: "arg: type" (:def function).
   * If "types_optional" is TRUE a missing type is OK, use "any".
   * If "evalarg" is not NULL use it to check for an already declared name.
+  * If "eap" is not NULL use it to check for an already declared name.
   * Return a pointer to after the type.
   * When something is wrong return "arg".
   */
***************
*** 65,70 ****
--- 66,72 ----
        garray_T    *argtypes,
        int         types_optional,
        evalarg_T   *evalarg,
+       exarg_T     *eap,
        int         is_vararg,
        int         skip)
  {
***************
*** 87,93 ****
      // Vim9 script: cannot use script var name for argument. In function: also
      // check local vars and arguments.
      if (!skip && argtypes != NULL && check_defined(arg, p - arg,
!                   evalarg == NULL ? NULL : evalarg->eval_cctx, TRUE) == FAIL)
        return arg;
  
      if (newargs != NULL && ga_grow(newargs, 1) == FAIL)
--- 89,96 ----
      // Vim9 script: cannot use script var name for argument. In function: also
      // check local vars and arguments.
      if (!skip && argtypes != NULL && check_defined(arg, p - arg,
!                              evalarg == NULL ? NULL : evalarg->eval_cctx,
!                              eap == NULL ? NULL : eap->cstack, TRUE) == FAIL)
        return arg;
  
      if (newargs != NULL && ga_grow(newargs, 1) == FAIL)
***************
*** 210,216 ****
      int               *varargs,
      garray_T  *default_args,
      int               skip,
!     exarg_T   *eap,
      garray_T  *lines_to_free)
  {
      int               mustend = FALSE;
--- 213,219 ----
      int               *varargs,
      garray_T  *default_args,
      int               skip,
!     exarg_T   *eap,           // can be NULL
      garray_T  *lines_to_free)
  {
      int               mustend = FALSE;
***************
*** 279,285 ****
  
                arg = p;
                p = one_function_arg(p, newargs, argtypes, types_optional,
!                                                         evalarg, TRUE, skip);
                if (p == arg)
                    break;
                if (*skipwhite(p) == '=')
--- 282,288 ----
  
                arg = p;
                p = one_function_arg(p, newargs, argtypes, types_optional,
!                                                    evalarg, eap, TRUE, skip);
                if (p == arg)
                    break;
                if (*skipwhite(p) == '=')
***************
*** 295,301 ****
  
            arg = p;
            p = one_function_arg(p, newargs, argtypes, types_optional,
!                                                        evalarg, FALSE, skip);
            if (p == arg)
                break;
  
--- 298,304 ----
  
            arg = p;
            p = one_function_arg(p, newargs, argtypes, types_optional,
!                                                   evalarg, eap, FALSE, skip);
            if (p == arg)
                break;
  
*** ../vim-8.2.4331/src/vim9compile.c   2022-02-07 21:53:58.085529486 +0000
--- src/vim9compile.c   2022-02-08 20:30:32.738346943 +0000
***************
*** 152,162 ****
   * Lookup a script-local variable in the current script, possibly defined in a
   * block that contains the function "cctx->ctx_ufunc".
   * "cctx" is NULL at the script level.
   * If "len" is <= 0 "name" must be NUL terminated.
   * Return NULL when not found.
   */
      static sallvar_T *
! find_script_var(char_u *name, size_t len, cctx_T *cctx)
  {
      scriptitem_T    *si = SCRIPT_ITEM(current_sctx.sc_sid);
      hashitem_T            *hi;
--- 152,163 ----
   * Lookup a script-local variable in the current script, possibly defined in a
   * block that contains the function "cctx->ctx_ufunc".
   * "cctx" is NULL at the script level.
+  * "cstack_T" is NULL in a function.
   * If "len" is <= 0 "name" must be NUL terminated.
   * Return NULL when not found.
   */
      static sallvar_T *
! find_script_var(char_u *name, size_t len, cctx_T *cctx, cstack_T *cstack)
  {
      scriptitem_T    *si = SCRIPT_ITEM(current_sctx.sc_sid);
      hashitem_T            *hi;
***************
*** 183,193 ****
  
      if (cctx == NULL)
      {
!       // Not in a function scope, find variable with block id equal to or
!       // smaller than the current block id.
        while (sav != NULL)
        {
!           if (sav->sav_block_id <= si->sn_current_block_id)
                break;
            sav = sav->sav_next;
        }
--- 184,205 ----
  
      if (cctx == NULL)
      {
!       // Not in a function scope, find variable with block ID equal to or
!       // smaller than the current block id.  If "cstack" is not NULL go up
!       // the block scopes (more accurate).
        while (sav != NULL)
        {
!           if (cstack != NULL)
!           {
!               int idx;
! 
!               for (idx = cstack->cs_idx; idx >= 0; --idx)
!                   if (cstack->cs_block_id[idx] == sav->sav_block_id)
!                       break;
!               if (idx >= 0)
!                   break;
!           }
!           else if (sav->sav_block_id <= si->sn_current_block_id)
                break;
            sav = sav->sav_next;
        }
***************
*** 225,234 ****
  /*
   * Lookup a variable (without s: prefix) in the current script.
   * "cctx" is NULL at the script level.
   * Returns OK or FAIL.
   */
      int
! script_var_exists(char_u *name, size_t len, cctx_T *cctx)
  {
      if (current_sctx.sc_sid <= 0)
        return FAIL;
--- 237,247 ----
  /*
   * Lookup a variable (without s: prefix) in the current script.
   * "cctx" is NULL at the script level.
+  * "cstack" is NULL in a function.
   * Returns OK or FAIL.
   */
      int
! script_var_exists(char_u *name, size_t len, cctx_T *cctx, cstack_T *cstack)
  {
      if (current_sctx.sc_sid <= 0)
        return FAIL;
***************
*** 236,242 ****
      {
        // Check script variables that were visible where the function was
        // defined.
!       if (find_script_var(name, len, cctx) != NULL)
            return OK;
      }
      else
--- 249,255 ----
      {
        // Check script variables that were visible where the function was
        // defined.
!       if (find_script_var(name, len, cctx, cstack) != NULL)
            return OK;
      }
      else
***************
*** 267,273 ****
      return (cctx != NULL
                && (lookup_local(name, len, NULL, cctx) == OK
                    || arg_exists(name, len, NULL, NULL, NULL, cctx) == OK))
!           || script_var_exists(name, len, cctx) == OK
            || find_imported(name, len, FALSE, cctx) != NULL;
  }
  
--- 280,286 ----
      return (cctx != NULL
                && (lookup_local(name, len, NULL, cctx) == OK
                    || arg_exists(name, len, NULL, NULL, NULL, cctx) == OK))
!           || script_var_exists(name, len, cctx, NULL) == OK
            || find_imported(name, len, FALSE, cctx) != NULL;
  }
  
***************
*** 309,315 ****
   * Return FAIL and give an error if it defined.
   */
      int
! check_defined(char_u *p, size_t len, cctx_T *cctx, int is_arg)
  {
      int               c = p[len];
      ufunc_T   *ufunc = NULL;
--- 322,333 ----
   * Return FAIL and give an error if it defined.
   */
      int
! check_defined(
!       char_u      *p,
!       size_t      len,
!       cctx_T      *cctx,
!       cstack_T    *cstack,
!       int         is_arg)
  {
      int               c = p[len];
      ufunc_T   *ufunc = NULL;
***************
*** 318,324 ****
      if (len == 1 && *p == '_')
        return OK;
  
!     if (script_var_exists(p, len, cctx) == OK)
      {
        if (is_arg)
            semsg(_(e_argument_already_declared_in_script_str), p);
--- 336,342 ----
      if (len == 1 && *p == '_')
        return OK;
  
!     if (script_var_exists(p, len, cctx, cstack) == OK)
      {
        if (is_arg)
            semsg(_(e_argument_already_declared_in_script_str), p);
***************
*** 526,532 ****
        return -1;
      if (sid == current_sctx.sc_sid)
      {
!       sallvar_T *sav = find_script_var(name, 0, cctx);
  
        if (sav == NULL)
            return -2;
--- 544,550 ----
        return -1;
      if (sid == current_sctx.sc_sid)
      {
!       sallvar_T *sav = find_script_var(name, 0, cctx, NULL);
  
        if (sav == NULL)
            return -2;
***************
*** 884,890 ****
        semsg(_(e_namespace_not_supported_str), name_start);
        return NULL;
      }
!     if (check_defined(name_start, name_end - name_start, cctx, FALSE) == FAIL)
        return NULL;
      if (!ASCII_ISUPPER(is_global ? name_start[2] : name_start[0]))
      {
--- 902,909 ----
        semsg(_(e_namespace_not_supported_str), name_start);
        return NULL;
      }
!     if (check_defined(name_start, name_end - name_start, cctx,
!                                                         NULL, FALSE) == FAIL)
        return NULL;
      if (!ASCII_ISUPPER(is_global ? name_start[2] : name_start[0]))
      {
***************
*** 1356,1364 ****
                                       && STRNCMP(var_start, "s:", 2) == 0;
                int script_var = (script_namespace
                        ? script_var_exists(var_start + 2, lhs->lhs_varlen - 2,
!                                                                         cctx)
                          : script_var_exists(var_start, lhs->lhs_varlen,
!                                                                 cctx)) == OK;
                imported_T  *import =
                        find_imported(var_start, lhs->lhs_varlen, FALSE, cctx);
  
--- 1375,1383 ----
                                       && STRNCMP(var_start, "s:", 2) == 0;
                int script_var = (script_namespace
                        ? script_var_exists(var_start + 2, lhs->lhs_varlen - 2,
!                                                                   cctx, NULL)
                          : script_var_exists(var_start, lhs->lhs_varlen,
!                                                           cctx, NULL)) == OK;
                imported_T  *import =
                        find_imported(var_start, lhs->lhs_varlen, FALSE, cctx);
  
***************
*** 1442,1449 ****
                        }
                    }
                }
!               else if (check_defined(var_start, lhs->lhs_varlen, cctx, FALSE)
!                                                                      == FAIL)
                    return FAIL;
            }
        }
--- 1461,1468 ----
                        }
                    }
                }
!               else if (check_defined(var_start, lhs->lhs_varlen, cctx,
!                                                         NULL, FALSE) == FAIL)
                    return FAIL;
            }
        }
***************
*** 2470,2476 ****
      for (i = 0; i < ufunc->uf_args.ga_len; ++i)
      {
        arg = ((char_u **)(ufunc->uf_args.ga_data))[i];
!       if (check_defined(arg, STRLEN(arg), cctx, TRUE) == FAIL)
        {
            r = FAIL;
            break;
--- 2489,2495 ----
      for (i = 0; i < ufunc->uf_args.ga_len; ++i)
      {
        arg = ((char_u **)(ufunc->uf_args.ga_data))[i];
!       if (check_defined(arg, STRLEN(arg), cctx, NULL, TRUE) == FAIL)
        {
            r = FAIL;
            break;
*** ../vim-8.2.4331/src/proto/vim9compile.pro   2022-02-02 16:20:22.386554561 
+0000
--- src/proto/vim9compile.pro   2022-02-08 20:29:00.926470151 +0000
***************
*** 2,9 ****
  int lookup_local(char_u *name, size_t len, lvar_T *lvar, cctx_T *cctx);
  int arg_exists(char_u *name, size_t len, int *idxp, type_T **type, int 
*gen_load_outer, cctx_T *cctx);
  int script_is_vim9(void);
! int script_var_exists(char_u *name, size_t len, cctx_T *cctx);
! int check_defined(char_u *p, size_t len, cctx_T *cctx, int is_arg);
  int need_type_where(type_T *actual, type_T *expected, int offset, where_T 
where, cctx_T *cctx, int silent, int actual_is_const);
  int need_type(type_T *actual, type_T *expected, int offset, int arg_idx, 
cctx_T *cctx, int silent, int actual_is_const);
  lvar_T *reserve_local(cctx_T *cctx, char_u *name, size_t len, int isConst, 
type_T *type);
--- 2,9 ----
  int lookup_local(char_u *name, size_t len, lvar_T *lvar, cctx_T *cctx);
  int arg_exists(char_u *name, size_t len, int *idxp, type_T **type, int 
*gen_load_outer, cctx_T *cctx);
  int script_is_vim9(void);
! int script_var_exists(char_u *name, size_t len, cctx_T *cctx, cstack_T 
*cstack);
! int check_defined(char_u *p, size_t len, cctx_T *cctx, cstack_T *cstack, int 
is_arg);
  int need_type_where(type_T *actual, type_T *expected, int offset, where_T 
where, cctx_T *cctx, int silent, int actual_is_const);
  int need_type(type_T *actual, type_T *expected, int offset, int arg_idx, 
cctx_T *cctx, int silent, int actual_is_const);
  lvar_T *reserve_local(cctx_T *cctx, char_u *name, size_t len, int isConst, 
type_T *type);
*** ../vim-8.2.4331/src/vim9script.c    2022-02-08 19:12:15.260593033 +0000
--- src/vim9script.c    2022-02-08 20:20:55.675136052 +0000
***************
*** 600,606 ****
            goto erret;
        }
        else if (imported == NULL
!               && check_defined(as_name, STRLEN(as_name), cctx, FALSE) == FAIL)
            goto erret;
  
        if (imported == NULL)
--- 600,607 ----
            goto erret;
        }
        else if (imported == NULL
!               && check_defined(as_name, STRLEN(as_name), cctx, NULL,
!                                                               FALSE) == FAIL)
            goto erret;
  
        if (imported == NULL)
*** ../vim-8.2.4331/src/vim9expr.c      2022-02-06 18:36:46.297746545 +0000
--- src/vim9expr.c      2022-02-08 20:23:39.622907487 +0000
***************
*** 501,507 ****
            {
                // "var" can be script-local even without using "s:" if it
                // already exists in a Vim9 script or when it's imported.
!               if (script_var_exists(*arg, len, cctx) == OK
                        || find_imported(name, 0, FALSE, cctx) != NULL)
                   res = compile_load_scriptvar(cctx, name, *arg, &end, FALSE);
  
--- 501,507 ----
            {
                // "var" can be script-local even without using "s:" if it
                // already exists in a Vim9 script or when it's imported.
!               if (script_var_exists(*arg, len, cctx, NULL) == OK
                        || find_imported(name, 0, FALSE, cctx) != NULL)
                   res = compile_load_scriptvar(cctx, name, *arg, &end, FALSE);
  
*** ../vim-8.2.4331/src/testdir/test_vim9_func.vim      2022-02-08 
19:23:31.712319067 +0000
--- src/testdir/test_vim9_func.vim      2022-02-08 20:03:40.448780266 +0000
***************
*** 1057,1062 ****
--- 1057,1099 ----
    END
    v9.CheckScriptSuccess(lines)
  
+   # with another variable in another block
+   lines =<< trim END
+     vim9script
+     if true
+       var name = 'piet'
+       # define a function so that the variable isn't cleared
+       def GetItem(): string
+         return item
+       enddef
+     endif
+     if true
+       var name = 'peter'
+       def FuncOne(name: string)
+         echo name
+       enddef
+     endif
+   END
+   v9.CheckScriptFailure(lines, 'E1168:')
+ 
+   # only variable in another block is OK
+   lines =<< trim END
+     vim9script
+     if true
+       var name = 'piet'
+       # define a function so that the variable isn't cleared
+       def GetItem(): string
+         return item
+       enddef
+     endif
+     if true
+       def FuncOne(name: string)
+         echo name
+       enddef
+     endif
+   END
+   v9.CheckScriptSuccess(lines)
+ 
    # argument name declared later is only found when compiling
    lines =<< trim END
      vim9script
*** ../vim-8.2.4331/src/version.c       2022-02-08 19:23:31.712319067 +0000
--- src/version.c       2022-02-08 20:00:27.981022674 +0000
***************
*** 748,749 ****
--- 748,751 ----
  {   /* Add new patch number below this line */
+ /**/
+     4332,
  /**/

-- 
How To Keep A Healthy Level Of Insanity:
3. Every time someone asks you to do something, ask if they want fries
   with that.

 /// 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/20220208203611.137501C1905%40moolenaar.net.

Raspunde prin e-mail lui