changeset 26504:7821550ba3a8 v8.2.3782

patch 8.2.3782: Vim9: no error if a function shadows a script variable Commit: https://github.com/vim/vim/commit/052ff291d72bc9c176f9562f021d7e8e030e74c0 Author: Bram Moolenaar <Bram@vim.org> Date: Sat Dec 11 13:54:46 2021 +0000 patch 8.2.3782: Vim9: no error if a function shadows a script variable Problem: Vim9: no error if a function shadows a script variable. Solution: Check the function doesn't shadow a variable. (closes https://github.com/vim/vim/issues/9310)
author Bram Moolenaar <Bram@vim.org>
date Sat, 11 Dec 2021 15:00:03 +0100
parents ae12de843776
children 6db198ec38ac
files src/evalvars.c src/testdir/test_vim9_script.vim src/userfunc.c src/version.c src/vim.h
diffstat 5 files changed, 46 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/src/evalvars.c
+++ b/src/evalvars.c
@@ -2712,7 +2712,7 @@ eval_variable(
 		type = sv->sv_type;
 	    }
 	}
-	else if (in_vim9script())
+	else if (in_vim9script() && (flags & EVAL_VAR_NO_FUNC) == 0)
 	{
 	    ufunc_T *ufunc = find_func(name, FALSE, NULL);
 
--- a/src/testdir/test_vim9_script.vim
+++ b/src/testdir/test_vim9_script.vim
@@ -1896,6 +1896,17 @@ def Test_script_var_shadows_function()
   CheckScriptFailure(lines, 'E1041:', 5)
 enddef
 
+def Test_function_shadows_script_var()
+  var lines =<< trim END
+      vim9script
+      var Func = 1
+      def Func(): number
+        return 123
+      enddef
+  END
+  CheckScriptFailure(lines, 'E1041:', 3)
+enddef
+
 def Test_script_var_shadows_command()
   var lines =<< trim END
       var undo = 1
@@ -2198,7 +2209,7 @@ def Test_func_overrules_import_fails()
       echo 'local to function'
     enddef
   END
-  CheckScriptFailure(lines, 'E1073:')
+  CheckScriptFailure(lines, 'E1041:')
 
   lines =<< trim END
     vim9script
@@ -2231,7 +2242,7 @@ def Test_func_redefine_fails()
     vim9script
     def Foo(): string
       return 'foo'
-      enddef
+    enddef
     def Func()
       var  Foo = {-> 'lambda'}
     enddef
--- a/src/userfunc.c
+++ b/src/userfunc.c
@@ -4134,19 +4134,41 @@ define_function(exarg_T *eap, char_u *na
 				     || (fudi.fd_di->di_tv.v_type != VAR_FUNC
 				 && fudi.fd_di->di_tv.v_type != VAR_PARTIAL)))
 	{
+	    char_u  *name_base = arg;
+	    int	    i;
+
 	    if (*arg == K_SPECIAL)
-		j = 3;
-	    else
-		j = 0;
-	    while (arg[j] != NUL && (j == 0 ? eval_isnamec1(arg[j])
-						      : eval_isnamec(arg[j])))
-		++j;
-	    if (arg[j] != NUL)
+	    {
+		name_base = vim_strchr(arg, '_');
+		if (name_base == NULL)
+		    name_base = arg + 3;
+		else
+		    ++name_base;
+	    }
+	    for (i = 0; name_base[i] != NUL && (i == 0
+					? eval_isnamec1(name_base[i])
+					: eval_isnamec(name_base[i])); ++i)
+		;
+	    if (name_base[i] != NUL)
 		emsg_funcname((char *)e_invarg2, arg);
+
+	    // In Vim9 script a function cannot have the same name as a
+	    // variable.
+	    if (vim9script && *arg == K_SPECIAL
+		     && eval_variable(name_base, STRLEN(name_base), NULL, NULL,
+			 EVAL_VAR_NOAUTOLOAD + EVAL_VAR_IMPORT
+						     + EVAL_VAR_NO_FUNC) == OK)
+	    {
+		semsg(_(e_redefining_script_item_str), name_base);
+		goto ret_free;
+	    }
 	}
 	// Disallow using the g: dict.
 	if (fudi.fd_dict != NULL && fudi.fd_dict->dv_scope == VAR_DEF_SCOPE)
+	{
 	    emsg(_("E862: Cannot use g: here"));
+	    goto ret_free;
+	}
     }
 
     // This may get more lines and make the pointers into the first line
--- a/src/version.c
+++ b/src/version.c
@@ -754,6 +754,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    3782,
+/**/
     3781,
 /**/
     3780,
--- a/src/vim.h
+++ b/src/vim.h
@@ -2782,6 +2782,7 @@ long elapsed(DWORD start_tick);
 #define EVAL_VAR_VERBOSE	1   // may give error message
 #define EVAL_VAR_NOAUTOLOAD	2   // do not use script autoloading
 #define EVAL_VAR_IMPORT		4   // may return special variable for import
+#define EVAL_VAR_NO_FUNC	8   // do not look for a function
 
 // Maximum number of characters that can be fuzzy matched
 #define MAX_FUZZY_MATCHES	256