# HG changeset patch # User Bram Moolenaar # Date 1637612103 -3600 # Node ID 14b4c778b61eb0adc173e23cc2dda7a3c64be474 # Parent 83c695dd5355ce602c1d4cee1eb5b13cee154aa9 patch 8.2.3650: Vim9: for loop variable can be a list member Commit: https://github.com/vim/vim/commit/3b3755fe19e9ded2a1c45f14b2c6fa065bcaf2c6 Author: Bram Moolenaar 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) diff --git a/src/dict.c b/src/dict.c --- 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; } diff --git a/src/eval.c b/src/eval.c --- 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) diff --git a/src/evalvars.c b/src/evalvars.c --- 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)) { diff --git a/src/proto/evalvars.pro b/src/proto/evalvars.pro --- 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); diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim --- 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 diff --git a/src/version.c b/src/version.c --- 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, diff --git a/src/vim9compile.c b/src/vim9compile.c --- 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);