]> granicus.if.org Git - vim/commitdiff
patch 8.2.3650: Vim9: for loop variable can be a list member v8.2.3650
authorBram Moolenaar <Bram@vim.org>
Mon, 22 Nov 2021 20:10:18 +0000 (20:10 +0000)
committerBram Moolenaar <Bram@vim.org>
Mon, 22 Nov 2021 20:10:18 +0000 (20:10 +0000)
Problem:    Vim9: for loop variable can be a list member.
Solution:   Check for valid variable name. (closes #9179)

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

index aa3c6113723bda7fac0929d7440e1aec3e057102..032c1b5a81403260c26c53ec61e90fd67e98da05 100644 (file)
@@ -1102,7 +1102,7 @@ dict_extend(dict_T *d1, dict_T *d2, char_u *action, char *func_name)
                        && 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;
            }
 
index 41291a24416913872299623263c9b84d34a59aaf..0e8b6a6776a806ce687ae4071865de1f410125e3 100644 (file)
@@ -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)
index afbab79ff461ee226a2b1165ecb3a03f81ecfee9..b56073453b6f238c202588114d761b59b7f2e646 100644 (file)
@@ -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, int use_gettext)
 
 /*
  * 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))
        {
index 58c12229569e8e1fcb3a889835498e87a5a3bf29..778506f88d5764cdb0d1c750b0526b106d6d14de 100644 (file)
@@ -78,7 +78,7 @@ int var_check_lock(int flags, char_u *name, int use_gettext);
 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);
index ca5d7beb08498aa8aa7bdb0261ba0f28c61562a9..989627f95f11ae13e91d506e6598f8e092e84331 100644 (file)
@@ -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
index 3851e8043f2453ba1fb6fbb596b8b7cf021a9532..121ce6eae9ba3aff3f8cea54c69372e9a8c76b65 100644 (file)
@@ -757,6 +757,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    3650,
 /**/
     3649,
 /**/
index 303b1e312786a4cb5c3b4ce2fd9a04b5ce1502cb..934f41b47af2f1290205f87b4784eaa23d25cda8 100644 (file)
@@ -8220,8 +8220,8 @@ compile_for(char_u *arg_start, cctx_T *cctx)
        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 *cctx)
            }
            else
            {
+               if (!valid_varname(arg, varlen, FALSE))
+                   goto failed;
                if (lookup_local(arg, varlen, NULL, cctx) == OK)
                {
                    semsg(_(e_variable_already_declared), arg);