Patch 8.2.1667
Problem:    Local function name cannot shadow a global function name.
Solution:   Ignore global functions when checking a script-local or scoped
            function name. (closes #6926)
Files:      src/vim9compile.c, src/userfunc.c, src/proto/userfunc.pro,
            src/testdir/test_vim9_func.vim


*** ../vim-8.2.1666/src/vim9compile.c   2020-09-10 22:27:57.805094402 +0200
--- src/vim9compile.c   2020-09-12 18:01:36.761426346 +0200
***************
*** 292,303 ****
  /*
   * Check if "p[len]" is already defined, either in script "import_sid" or in
   * compilation context "cctx".
   * Return FAIL and give an error if it defined.
   */
      int
  check_defined(char_u *p, size_t len, cctx_T *cctx)
  {
!     int c = p[len];
  
      p[len] = NUL;
      if (lookup_script(p, len, FALSE) == OK
--- 292,305 ----
  /*
   * Check if "p[len]" is already defined, either in script "import_sid" or in
   * compilation context "cctx".
+  * Does not check the global namespace.
   * Return FAIL and give an error if it defined.
   */
      int
  check_defined(char_u *p, size_t len, cctx_T *cctx)
  {
!     int               c = p[len];
!     ufunc_T   *ufunc = NULL;
  
      p[len] = NUL;
      if (lookup_script(p, len, FALSE) == OK
***************
*** 305,315 ****
                && (lookup_local(p, len, cctx) != NULL
                    || lookup_arg(p, len, NULL, NULL, NULL, cctx) == OK))
            || find_imported(p, len, cctx) != NULL
!           || find_func_even_dead(p, FALSE, cctx) != NULL)
      {
!       p[len] = c;
!       semsg(_(e_name_already_defined_str), p);
!       return FAIL;
      }
      p[len] = c;
      return OK;
--- 307,322 ----
                && (lookup_local(p, len, cctx) != NULL
                    || lookup_arg(p, len, NULL, NULL, NULL, cctx) == OK))
            || find_imported(p, len, cctx) != NULL
!           || (ufunc = find_func_even_dead(p, FALSE, cctx)) != NULL)
      {
!       // A local or script-local function can shadow a global function.
!       if (ufunc == NULL || !func_is_global(ufunc)
!               || (p[0] == 'g' && p[1] == ':'))
!       {
!           p[len] = c;
!           semsg(_(e_name_already_defined_str), p);
!           return FAIL;
!       }
      }
      p[len] = c;
      return OK;
***************
*** 2114,2123 ****
  /*
   * Compile a variable name into a load instruction.
   * "end" points to just after the name.
   * When "error" is FALSE do not give an error when not found.
   */
      static int
! compile_load(char_u **arg, char_u *end_arg, cctx_T *cctx, int error)
  {
      type_T    *type;
      char_u    *name = NULL;
--- 2121,2136 ----
  /*
   * Compile a variable name into a load instruction.
   * "end" points to just after the name.
+  * "is_expr" is TRUE when evaluating an expression, might be a funcref.
   * When "error" is FALSE do not give an error when not found.
   */
      static int
! compile_load(
!       char_u **arg,
!       char_u *end_arg,
!       cctx_T  *cctx,
!       int     is_expr,
!       int     error)
  {
      type_T    *type;
      char_u    *name = NULL;
***************
*** 2214,2223 ****
                        || find_imported(name, 0, cctx) != NULL)
                   res = compile_load_scriptvar(cctx, name, *arg, &end, FALSE);
  
!               // When the name starts with an uppercase letter or "x:" it
!               // can be a user defined function.
                // TODO: this is just guessing
!               if (res == FAIL && (ASCII_ISUPPER(*name) || name[1] == ':'))
                    res = generate_funcref(cctx, name);
            }
        }
--- 2227,2237 ----
                        || find_imported(name, 0, cctx) != NULL)
                   res = compile_load_scriptvar(cctx, name, *arg, &end, FALSE);
  
!               // When evaluating an expression and the name starts with an
!               // uppercase letter or "x:" it can be a user defined function.
                // TODO: this is just guessing
!               if (res == FAIL && is_expr
!                                  && (ASCII_ISUPPER(*name) || name[1] == ':'))
                    res = generate_funcref(cctx, name);
            }
        }
***************
*** 2368,2375 ****
      }
  
      // If we can find the function by name generate the right call.
      ufunc = find_func(name, FALSE, cctx);
!     if (ufunc != NULL)
      {
        res = generate_CALL(cctx, ufunc, argcount);
        goto theend;
--- 2382,2390 ----
      }
  
      // If we can find the function by name generate the right call.
+     // Skip global functions here, a local funcref takes precedence.
      ufunc = find_func(name, FALSE, cctx);
!     if (ufunc != NULL && !func_is_global(ufunc))
      {
        res = generate_CALL(cctx, ufunc, argcount);
        goto theend;
***************
*** 2380,2386 ****
      // Not for eome#Func(), it will be loaded later.
      p = namebuf;
      if (STRNCMP(namebuf, "g:", 2) != 0 && !is_autoload
!           && compile_load(&p, namebuf + varlen, cctx, FALSE) == OK)
      {
        garray_T    *stack = &cctx->ctx_type_stack;
        type_T      *type;
--- 2395,2401 ----
      // Not for eome#Func(), it will be loaded later.
      p = namebuf;
      if (STRNCMP(namebuf, "g:", 2) != 0 && !is_autoload
!           && compile_load(&p, namebuf + varlen, cctx, FALSE, FALSE) == OK)
      {
        garray_T    *stack = &cctx->ctx_type_stack;
        type_T      *type;
***************
*** 2390,2395 ****
--- 2405,2417 ----
        goto theend;
      }
  
+     // If we can find a global function by name generate the right call.
+     if (ufunc != NULL)
+     {
+       res = generate_CALL(cctx, ufunc, argcount);
+       goto theend;
+     }
+ 
      // A global function may be defined only later.  Need to figure out at
      // runtime.  Also handles a FuncRef at runtime.
      if (STRNCMP(namebuf, "g:", 2) == 0 || is_autoload)
***************
*** 3548,3554 ****
        {
            if (generate_ppconst(cctx, ppconst) == FAIL)
                return FAIL;
!           r = compile_load(arg, p, cctx, TRUE);
        }
        if (r == FAIL)
            return FAIL;
--- 3570,3576 ----
        {
            if (generate_ppconst(cctx, ppconst) == FAIL)
                return FAIL;
!           r = compile_load(arg, p, cctx, TRUE, TRUE);
        }
        if (r == FAIL)
            return FAIL;
***************
*** 5002,5007 ****
--- 5024,5034 ----
                              : ((type_T **)stack->ga_data)[stack->ga_len - 1];
                if (lvar != NULL && (is_decl || !has_type))
                {
+                   if ((stacktype->tt_type == VAR_FUNC
+                               || stacktype->tt_type == VAR_PARTIAL)
+                           && var_wrong_func_name(name, TRUE))
+                       goto theend;
+ 
                    if (new_local && !has_type)
                    {
                        if (stacktype->tt_type == VAR_VOID)
***************
*** 5009,5020 ****
                            emsg(_(e_cannot_use_void_value));
                            goto theend;
                        }
-                       else if ((stacktype->tt_type == VAR_FUNC
-                                   || stacktype->tt_type == VAR_PARTIAL)
-                                           && var_wrong_func_name(name, TRUE))
-                       {
-                           goto theend;
-                       }
                        else
                        {
                            // An empty list or dict has a &t_void member,
--- 5036,5041 ----
*** ../vim-8.2.1666/src/userfunc.c      2020-09-09 17:08:47.561323027 +0200
--- src/userfunc.c      2020-09-12 16:24:13.974826974 +0200
***************
*** 875,880 ****
--- 875,889 ----
  }
  
  /*
+  * Return TRUE if "ufunc" is a global function.
+  */
+     int
+ func_is_global(ufunc_T *ufunc)
+ {
+     return ufunc->uf_name[0] != K_SPECIAL;
+ }
+ 
+ /*
   * Copy the function name of "fp" to buffer "buf".
   * "buf" must be able to hold the function name plus three bytes.
   * Takes care of script-local function names.
***************
*** 882,888 ****
      static void
  cat_func_name(char_u *buf, ufunc_T *fp)
  {
!     if (fp->uf_name[0] == K_SPECIAL)
      {
        STRCPY(buf, "<SNR>");
        STRCAT(buf, fp->uf_name + 3);
--- 891,897 ----
      static void
  cat_func_name(char_u *buf, ufunc_T *fp)
  {
!     if (!func_is_global(fp))
      {
        STRCPY(buf, "<SNR>");
        STRCAT(buf, fp->uf_name + 3);
*** ../vim-8.2.1666/src/proto/userfunc.pro      2020-08-20 15:02:38.536534973 
+0200
--- src/proto/userfunc.pro      2020-09-12 16:24:17.278817909 +0200
***************
*** 11,16 ****
--- 11,17 ----
  char_u *fname_trans_sid(char_u *name, char_u *fname_buf, char_u **tofree, int 
*error);
  ufunc_T *find_func_even_dead(char_u *name, int is_global, cctx_T *cctx);
  ufunc_T *find_func(char_u *name, int is_global, cctx_T *cctx);
+ int func_is_global(ufunc_T *ufunc);
  void copy_func(char_u *lambda, char_u *global);
  int call_user_func_check(ufunc_T *fp, int argcount, typval_T *argvars, 
typval_T *rettv, funcexe_T *funcexe, dict_T *selfdict);
  void save_funccal(funccal_entry_T *entry);
*** ../vim-8.2.1666/src/testdir/test_vim9_func.vim      2020-09-11 
19:09:42.095873318 +0200
--- src/testdir/test_vim9_func.vim      2020-09-12 18:26:49.076482289 +0200
***************
*** 232,237 ****
--- 232,267 ----
    CheckScriptFailure(lines, 'E117:')
  enddef
  
+ def Test_local_function_shadows_global()
+   let lines =<< trim END
+       vim9script
+       def g:Gfunc(): string
+         return 'global'
+       enddef
+       def AnotherFunc(): number
+         let Gfunc = function('len')
+         return Gfunc('testing')
+       enddef
+       g:Gfunc()->assert_equal('global')
+       AnotherFunc()->assert_equal(7)
+       delfunc g:Gfunc
+   END
+   CheckScriptSuccess(lines)
+ 
+   lines =<< trim END
+       vim9script
+       def g:Func(): string
+         return 'global'
+       enddef
+       def AnotherFunc()
+         g:Func = function('len')
+       enddef
+       AnotherFunc()
+   END
+   CheckScriptFailure(lines, 'E705:')
+   delfunc g:Func
+ enddef
+ 
  func TakesOneArg(arg)
    echo a:arg
  endfunc
*** ../vim-8.2.1666/src/version.c       2020-09-12 14:53:45.802973526 +0200
--- src/version.c       2020-09-12 18:29:59.375893929 +0200
***************
*** 752,753 ****
--- 752,755 ----
  {   /* Add new patch number below this line */
+ /**/
+     1667,
  /**/

-- 
There is no right or wrong, there is only your personal opinion.
                 (Bram Moolenaar)

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\  an exciting new programming language -- http://www.Zimbu.org        ///
 \\\            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/202009121633.08CGX4od1159071%40masaka.moolenaar.net.

Raspunde prin e-mail lui