changeset 27267:322b79b002b7 v8.2.4162

patch 8.2.4162: Vim9: no error for redefining function with export Commit: https://github.com/vim/vim/commit/9c7cae66bc21a3dc5c6e60cd64216ce7c9073003 Author: Bram Moolenaar <Bram@vim.org> Date: Thu Jan 20 19:10:25 2022 +0000 patch 8.2.4162: Vim9: no error for redefining function with export Problem: Vim9: no error for redefining function with export. Solution: Check for existing function with/without prefix. (closes https://github.com/vim/vim/issues/9577)
author Bram Moolenaar <Bram@vim.org>
date Thu, 20 Jan 2022 20:15:03 +0100
parents 06a2610c1661
children c97e40973b62
files src/scriptfile.c src/testdir/test_vim9_import.vim src/userfunc.c src/version.c
diffstat 4 files changed, 129 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/src/scriptfile.c
+++ b/src/scriptfile.c
@@ -2190,7 +2190,7 @@ get_autoload_prefix(scriptitem_T *si)
 
 /*
  * If in a Vim9 autoload script return "name" with the autoload prefix for the
- * script.  If successful "name" is freed, the returned name is allocated.
+ * script.  If successful the returned name is allocated.
  * Otherwise it returns "name" unmodified.
  */
     char_u *
@@ -2221,7 +2221,6 @@ may_prefix_autoload(char_u *name)
 	    {
 		vim_snprintf((char *)res, len, "%s%s",
 					     si->sn_autoload_prefix, basename);
-		vim_free(name);
 		return res;
 	    }
 	}
--- a/src/testdir/test_vim9_import.vim
+++ b/src/testdir/test_vim9_import.vim
@@ -1440,6 +1440,80 @@ def Test_vim9script_autoload_call()
   &rtp = save_rtp
 enddef
 
+def Test_vim9script_autoload_duplicate()
+  mkdir('Xdir/autoload', 'p')
+
+  var lines =<< trim END
+     vim9script
+
+     export def Func()
+     enddef
+
+     def Func()
+     enddef
+  END
+  writefile(lines, 'Xdir/autoload/dupfunc.vim')
+  assert_fails('source Xdir/autoload/dupfunc.vim', 'E1073:')
+
+  lines =<< trim END
+     vim9script
+
+     def Func()
+     enddef
+
+     export def Func()
+     enddef
+  END
+  writefile(lines, 'Xdir/autoload/dup2func.vim')
+  assert_fails('source Xdir/autoload/dup2func.vim', 'E1073:')
+
+  lines =<< trim END
+     vim9script
+
+     def Func()
+     enddef
+
+     export var Func = 'asdf'
+  END
+  writefile(lines, 'Xdir/autoload/dup3func.vim')
+  assert_fails('source Xdir/autoload/dup3func.vim', 'E1041: Redefining script item Func')
+
+  lines =<< trim END
+     vim9script
+
+     export var Func = 'asdf'
+
+     def Func()
+     enddef
+  END
+  writefile(lines, 'Xdir/autoload/dup4func.vim')
+  assert_fails('source Xdir/autoload/dup4func.vim', 'E707:')
+
+  lines =<< trim END
+     vim9script
+
+     var Func = 'asdf'
+
+     export def Func()
+     enddef
+  END
+  writefile(lines, 'Xdir/autoload/dup5func.vim')
+  assert_fails('source Xdir/autoload/dup5func.vim', 'E707:')
+
+  lines =<< trim END
+     vim9script
+
+     export def Func()
+     enddef
+
+     var Func = 'asdf'
+  END
+  writefile(lines, 'Xdir/autoload/dup6func.vim')
+  assert_fails('source Xdir/autoload/dup6func.vim', 'E1041: Redefining script item Func')
+
+  delete('Xdir', 'rf')
+enddef
+
 def Test_import_autoload_postponed()
   mkdir('Xdir/autoload', 'p')
   var save_rtp = &rtp
--- a/src/userfunc.c
+++ b/src/userfunc.c
@@ -1911,6 +1911,12 @@ find_func_with_prefix(char_u *name, int 
     {
 	size_t	len = STRLEN(si->sn_autoload_prefix) + STRLEN(name) + 1;
 	char_u	*auto_name;
+	char_u	*namep;
+
+	// skip a "<SNR>99_" prefix
+	namep = untrans_function_name(name);
+	if (namep == NULL)
+	    namep = name;
 
 	// An exported function in an autoload script is stored as
 	// "dir#path#name".
@@ -1921,7 +1927,7 @@ find_func_with_prefix(char_u *name, int 
 	if (auto_name != NULL)
 	{
 	    vim_snprintf((char *)auto_name, len, "%s%s",
-						 si->sn_autoload_prefix, name);
+						si->sn_autoload_prefix, namep);
 	    hi = hash_find(&func_hashtab, auto_name);
 	    if (auto_name != buffer)
 		vim_free(auto_name);
@@ -4175,7 +4181,15 @@ define_function(exarg_T *eap, char_u *na
 	// is stored with the legacy autoload name "dir#script#FuncName" so
 	// that it can also be found in legacy script.
 	if (is_export && name != NULL)
-	    name = may_prefix_autoload(name);
+	{
+	    char_u *prefixed = may_prefix_autoload(name);
+
+	    if (prefixed != NULL && prefixed != name)
+	    {
+		vim_free(name);
+		name = prefixed;
+	    }
+	}
     }
 
     // An error in a function call during evaluation of an expression in magic
@@ -4447,20 +4461,53 @@ define_function(exarg_T *eap, char_u *na
     if (fudi.fd_dict == NULL)
     {
 	hashtab_T	*ht;
+	char_u		*find_name = name;
+	int		var_conflict = FALSE;
 
 	v = find_var(name, &ht, TRUE);
-	if (v != NULL && v->di_tv.v_type == VAR_FUNC)
+	if (v != NULL)
+	    var_conflict = TRUE;
+
+	if (SCRIPT_ID_VALID(current_sctx.sc_sid))
+	{
+	    scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid);
+
+	    if (si->sn_autoload_prefix != NULL)
+	    {
+		if (is_export)
+		{
+		    find_name = name + STRLEN(si->sn_autoload_prefix);
+		    v = find_var(find_name, &ht, TRUE);
+		    if (v != NULL)
+			var_conflict = TRUE;
+		}
+		else
+		{
+		    char_u *prefixed = may_prefix_autoload(name);
+
+		    if (prefixed != NULL)
+		    {
+			v = find_var(prefixed, &ht, TRUE);
+			if (v != NULL)
+			    var_conflict = TRUE;
+			vim_free(prefixed);
+		    }
+		}
+	    }
+	}
+	if (var_conflict)
 	{
 	    emsg_funcname(e_function_name_conflicts_with_variable_str, name);
 	    goto erret;
 	}
 
-	fp = find_func_even_dead(name, is_global);
+	fp = find_func_even_dead(find_name, is_global);
 	if (vim9script)
 	{
 	    char_u *uname = untrans_function_name(name);
 
-	    import = find_imported(uname == NULL ? name : uname, 0, FALSE, NULL);
+	    import = find_imported(uname == NULL ? name : uname, 0,
+								  FALSE, NULL);
 	}
 
 	if (fp != NULL || import != NULL)
--- a/src/version.c
+++ b/src/version.c
@@ -751,6 +751,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    4162,
+/**/
     4161,
 /**/
     4160,