changeset 26238:14b4c778b61e v8.2.3650

patch 8.2.3650: Vim9: for loop variable can be a list member Commit: https://github.com/vim/vim/commit/3b3755fe19e9ded2a1c45f14b2c6fa065bcaf2c6 Author: Bram Moolenaar <Bram@vim.org> Date: Mon Nov 22 20:10:18 2021 +0000 patch 8.2.3650: Vim9: for loop variable can be a list member Problem: Vim9: for loop variable can be a list member. Solution: Check for valid variable name. (closes https://github.com/vim/vim/issues/9179)
author Bram Moolenaar <Bram@vim.org>
date Mon, 22 Nov 2021 21:15:03 +0100
parents 83c695dd5355
children 5187470e768c
files src/dict.c src/eval.c src/evalvars.c src/proto/evalvars.pro src/testdir/test_vim9_script.vim src/version.c src/vim9compile.c
diffstat 7 files changed, 38 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/src/dict.c
+++ b/src/dict.c
@@ -1102,7 +1102,7 @@ dict_extend(dict_T *d1, dict_T *d2, char
 			&& HI2DI(hi2)->di_tv.v_type == VAR_FUNC
 			&& var_wrong_func_name(hi2->hi_key, di1 == NULL))
 		    break;
-		if (!valid_varname(hi2->hi_key, TRUE))
+		if (!valid_varname(hi2->hi_key, -1, TRUE))
 		    break;
 	    }
 
--- a/src/eval.c
+++ b/src/eval.c
@@ -1128,7 +1128,7 @@ get_lval(
 		wrong = (lp->ll_dict->dv_scope == VAR_DEF_SCOPE
 			       && rettv->v_type == VAR_FUNC
 			       && var_wrong_func_name(key, lp->ll_di == NULL))
-			|| !valid_varname(key, TRUE);
+			|| !valid_varname(key, -1, TRUE);
 		if (len != -1)
 		    key[len] = prevval;
 		if (wrong)
--- a/src/evalvars.c
+++ b/src/evalvars.c
@@ -3431,7 +3431,7 @@ set_var_const(
 
 	    // Make sure the variable name is valid.  In Vim9 script an autoload
 	    // variable must be prefixed with "g:".
-	    if (!valid_varname(varname, !vim9script
+	    if (!valid_varname(varname, -1, !vim9script
 					       || STRNCMP(name, "g:", 2) == 0))
 		goto failed;
 
@@ -3631,14 +3631,15 @@ value_check_lock(int lock, char_u *name,
 
 /*
  * Check if a variable name is valid.  When "autoload" is true "#" is allowed.
+ * If "len" is -1 use all of "varname", otherwise up to "varname[len]".
  * Return FALSE and give an error if not.
  */
     int
-valid_varname(char_u *varname, int autoload)
+valid_varname(char_u *varname, int len, int autoload)
 {
     char_u *p;
 
-    for (p = varname; *p != NUL; ++p)
+    for (p = varname; len < 0 ? *p != NUL : p < varname + len; ++p)
 	if (!eval_isnamec1(*p) && (p == varname || !VIM_ISDIGIT(*p))
 					 && !(autoload && *p == AUTOLOAD_CHAR))
 	{
--- a/src/proto/evalvars.pro
+++ b/src/proto/evalvars.pro
@@ -78,7 +78,7 @@ int var_check_lock(int flags, char_u *na
 int var_check_fixed(int flags, char_u *name, int use_gettext);
 int var_wrong_func_name(char_u *name, int new_var);
 int value_check_lock(int lock, char_u *name, int use_gettext);
-int valid_varname(char_u *varname, int autoload);
+int valid_varname(char_u *varname, int len, int autoload);
 void reset_v_option_vars(void);
 void assert_error(garray_T *gap);
 int var_exists(char_u *var);
--- a/src/testdir/test_vim9_script.vim
+++ b/src/testdir/test_vim9_script.vim
@@ -2865,11 +2865,35 @@ def Test_for_loop_fails()
       endfor
   END
   CheckDefExecAndScriptFailure(lines, 'E1012: Type mismatch; expected job but got string', 2)
+
+  lines =<< trim END
+      var i = 0
+      for i in [1, 2, 3]
+        echo i
+      endfor
+  END
+  CheckDefExecAndScriptFailure2(lines, 'E1017:', 'E1041:')
+
+  lines =<< trim END
+      var l = [0]
+      for l[0] in [1, 2, 3]
+        echo l[0]
+      endfor
+  END
+  CheckDefExecAndScriptFailure2(lines, 'E461:', 'E1017:')
+
+  lines =<< trim END
+      var d = {x: 0}
+      for d.x in [1, 2, 3]
+        echo d.x
+      endfor
+  END
+  CheckDefExecAndScriptFailure2(lines, 'E461:', 'E1017:')
 enddef
 
 def Test_for_loop_script_var()
   # cannot use s:var in a :def function
-  CheckDefFailure(['for s:var in range(3)', 'echo 3'], 'E1101:')
+  CheckDefFailure(['for s:var in range(3)', 'echo 3'], 'E461:')
 
   # can use s:var in Vim9 script, with or without s:
   var lines =<< trim END
--- a/src/version.c
+++ b/src/version.c
@@ -758,6 +758,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    3650,
+/**/
     3649,
 /**/
     3648,
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -8220,8 +8220,8 @@ compile_for(char_u *arg_start, cctx_T *c
 	for (idx = 0; idx < var_count; ++idx)
 	{
 	    assign_dest_T	dest = dest_local;
-	    int		opt_flags = 0;
-	    int		vimvaridx = -1;
+	    int			opt_flags = 0;
+	    int			vimvaridx = -1;
 	    type_T		*type = &t_any;
 	    type_T		*lhs_type = &t_any;
 	    where_T		where = WHERE_INIT;
@@ -8255,6 +8255,8 @@ compile_for(char_u *arg_start, cctx_T *c
 	    }
 	    else
 	    {
+		if (!valid_varname(arg, varlen, FALSE))
+		    goto failed;
 		if (lookup_local(arg, varlen, NULL, cctx) == OK)
 		{
 		    semsg(_(e_variable_already_declared), arg);