To: vim_dev@googlegroups.com Subject: Patch 8.2.2760 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.2760 Problem: Vim9: no error for changing a for loop variable. Solution: Make the loop variable read-only. (issue #8102) Files: src/eval.c, src/evalvars.c, src/vim9compile.c, src/vim.h, src/testdir/test_vim9_script.vim *** ../vim-8.2.2759/src/eval.c 2021-04-12 21:20:58.634708976 +0200 --- src/eval.c 2021-04-13 21:33:38.330057046 +0200 *************** *** 1351,1357 **** { typval_T tv; ! if (flags & (ASSIGN_CONST | ASSIGN_FINAL)) { emsg(_(e_cannot_mod)); *endp = cc; --- 1351,1358 ---- { typval_T tv; ! if ((flags & (ASSIGN_CONST | ASSIGN_FINAL)) ! && (flags & ASSIGN_FOR_LOOP) == 0) { emsg(_(e_cannot_mod)); *endp = cc; *************** *** 1390,1396 **** listitem_T *ll_li = lp->ll_li; int ll_n1 = lp->ll_n1; ! if (flags & (ASSIGN_CONST | ASSIGN_FINAL)) { emsg(_("E996: Cannot lock a range")); return; --- 1391,1398 ---- listitem_T *ll_li = lp->ll_li; int ll_n1 = lp->ll_n1; ! if ((flags & (ASSIGN_CONST | ASSIGN_FINAL)) ! && (flags & ASSIGN_FOR_LOOP) == 0) { emsg(_("E996: Cannot lock a range")); return; *************** *** 1449,1455 **** /* * Assign to a List or Dictionary item. */ ! if (flags & (ASSIGN_CONST | ASSIGN_FINAL)) { emsg(_("E996: Cannot lock a list or dict")); return; --- 1451,1458 ---- /* * Assign to a List or Dictionary item. */ ! if ((flags & (ASSIGN_CONST | ASSIGN_FINAL)) ! && (flags & ASSIGN_FOR_LOOP) == 0) { emsg(_("E996: Cannot lock a list or dict")); return; *************** *** 1775,1781 **** { forinfo_T *fi = (forinfo_T *)fi_void; int result; ! int flag = in_vim9script() ? ASSIGN_DECL : 0; listitem_T *item; if (fi->fi_blob != NULL) --- 1778,1786 ---- { forinfo_T *fi = (forinfo_T *)fi_void; int result; ! int flag = ASSIGN_FOR_LOOP | (in_vim9script() ! ? (ASSIGN_FINAL | ASSIGN_DECL | ASSIGN_NO_MEMBER_TYPE) ! : 0); listitem_T *item; if (fi->fi_blob != NULL) *** ../vim-8.2.2759/src/evalvars.c 2021-04-10 22:35:40.487360271 +0200 --- src/evalvars.c 2021-04-13 21:44:23.604852104 +0200 *************** *** 1315,1321 **** // ":let $VAR = expr": Set environment variable. if (*arg == '$') { ! if (flags & (ASSIGN_CONST | ASSIGN_FINAL)) { emsg(_("E996: Cannot lock an environment variable")); return NULL; --- 1315,1322 ---- // ":let $VAR = expr": Set environment variable. if (*arg == '$') { ! if ((flags & (ASSIGN_CONST | ASSIGN_FINAL)) ! && (flags & ASSIGN_FOR_LOOP) == 0) { emsg(_("E996: Cannot lock an environment variable")); return NULL; *************** *** 1365,1373 **** // ":let &option = expr": Set option value. // ":let &l:option = expr": Set local option value. // ":let &g:option = expr": Set global option value. else if (*arg == '&') { ! if (flags & (ASSIGN_CONST | ASSIGN_FINAL)) { emsg(_(e_const_option)); return NULL; --- 1366,1376 ---- // ":let &option = expr": Set option value. // ":let &l:option = expr": Set local option value. // ":let &g:option = expr": Set global option value. + // ":for &ts in range(8)": Set option value for for loop else if (*arg == '&') { ! if ((flags & (ASSIGN_CONST | ASSIGN_FINAL)) ! && (flags & ASSIGN_FOR_LOOP) == 0) { emsg(_(e_const_option)); return NULL; *************** *** 1466,1472 **** // ":let @r = expr": Set register contents. else if (*arg == '@') { ! if (flags & (ASSIGN_CONST | ASSIGN_FINAL)) { emsg(_("E996: Cannot lock a register")); return NULL; --- 1469,1476 ---- // ":let @r = expr": Set register contents. else if (*arg == '@') { ! if ((flags & (ASSIGN_CONST | ASSIGN_FINAL)) ! && (flags & ASSIGN_FOR_LOOP) == 0) { emsg(_("E996: Cannot lock a register")); return NULL; *************** *** 3158,3164 **** type_T *type, typval_T *tv_arg, int copy, // make copy of value in "tv" ! int flags, // ASSIGN_CONST, ASSIGN_FINAL, etc. int var_idx) // index for ":let [a, b] = list" { typval_T *tv = tv_arg; --- 3162,3168 ---- type_T *type, typval_T *tv_arg, int copy, // make copy of value in "tv" ! int flags_arg, // ASSIGN_CONST, ASSIGN_FINAL, etc. int var_idx) // index for ":let [a, b] = list" { typval_T *tv = tv_arg; *************** *** 3169,3174 **** --- 3173,3179 ---- int is_script_local; int vim9script = in_vim9script(); int var_in_vim9script; + int flags = flags_arg; ht = find_var_ht(name, &varname); if (ht == NULL || *varname == NUL) *************** *** 3187,3192 **** --- 3192,3202 ---- vim9_declare_error(name); goto failed; } + if ((flags & ASSIGN_FOR_LOOP) && name[1] == ':' + && vim_strchr((char_u *)"gwbt", name[0]) != NULL) + // Do not make g:var, w:var, b:var or t:var final. + flags &= ~ASSIGN_FINAL; + var_in_vim9script = is_script_local && current_script_is_vim9(); if (var_in_vim9script && name[0] == '_' && name[1] == NUL) { *************** *** 3220,3226 **** // Item already exists. Allowed to replace when reloading. if ((di->di_flags & DI_FLAGS_RELOAD) == 0) { ! if (flags & (ASSIGN_CONST | ASSIGN_FINAL)) { emsg(_(e_cannot_mod)); goto failed; --- 3230,3237 ---- // Item already exists. Allowed to replace when reloading. if ((di->di_flags & DI_FLAGS_RELOAD) == 0) { ! if ((flags & (ASSIGN_CONST | ASSIGN_FINAL)) ! && (flags & ASSIGN_FOR_LOOP) == 0) { emsg(_(e_cannot_mod)); goto failed; *************** *** 3255,3261 **** // A Vim9 script-local variable is also present in sn_all_vars and // sn_var_vals. It may set "type" from "tv". if (var_in_vim9script) ! update_vim9_script_var(FALSE, di, flags, tv, &type); } // existing variable, need to clear the value --- 3266,3273 ---- // A Vim9 script-local variable is also present in sn_all_vars and // sn_var_vals. It may set "type" from "tv". if (var_in_vim9script) ! update_vim9_script_var(FALSE, di, flags, tv, &type, ! (flags & ASSIGN_NO_MEMBER_TYPE) == 0); } // existing variable, need to clear the value *************** *** 3353,3359 **** // A Vim9 script-local variable is also added to sn_all_vars and // sn_var_vals. It may set "type" from "tv". if (var_in_vim9script) ! update_vim9_script_var(TRUE, di, flags, tv, &type); } if (copy || tv->v_type == VAR_NUMBER || tv->v_type == VAR_FLOAT) --- 3365,3372 ---- // A Vim9 script-local variable is also added to sn_all_vars and // sn_var_vals. It may set "type" from "tv". if (var_in_vim9script) ! update_vim9_script_var(TRUE, di, flags, tv, &type, ! (flags & ASSIGN_NO_MEMBER_TYPE) == 0); } if (copy || tv->v_type == VAR_NUMBER || tv->v_type == VAR_FLOAT) *** ../vim-8.2.2759/src/vim9compile.c 2021-04-12 21:20:58.634708976 +0200 --- src/vim9compile.c 2021-04-13 21:17:49.447983964 +0200 *************** *** 7590,7596 **** // Reserve a variable to store "var". // TODO: check for type ! var_lvar = reserve_local(cctx, arg, varlen, FALSE, &t_any); if (var_lvar == NULL) // out of memory or used as an argument goto failed; --- 7590,7596 ---- // Reserve a variable to store "var". // TODO: check for type ! var_lvar = reserve_local(cctx, arg, varlen, TRUE, &t_any); if (var_lvar == NULL) // out of memory or used as an argument goto failed; *** ../vim-8.2.2759/src/vim.h 2021-04-13 20:53:09.846201149 +0200 --- src/vim.h 2021-04-13 21:27:01.150065988 +0200 *************** *** 2158,2163 **** --- 2158,2164 ---- #define ASSIGN_DECL 0x08 // may declare variable if it does not exist #define ASSIGN_UNPACK 0x10 // using [a, b] = list #define ASSIGN_NO_MEMBER_TYPE 0x20 // use "any" for list and dict member type + #define ASSIGN_FOR_LOOP 0x40 // assigning to loop variable #include "ex_cmds.h" // Ex command defines #include "spell.h" // spell checking stuff *** ../vim-8.2.2759/src/testdir/test_vim9_script.vim 2021-04-13 20:53:09.846201149 +0200 --- src/testdir/test_vim9_script.vim 2021-04-13 21:19:45.107564578 +0200 *************** *** 2393,2398 **** --- 2393,2406 ---- g:adict = {a: 1} CheckDefExecFailure(['for i in g:adict', 'echo 3', 'endfor'], 'E1177: For loop on dict not supported') unlet g:adict + + var lines =<< trim END + var d: list> = [{a: 0}] + for e in d + e = {a: 0, b: ''} + endfor + END + CheckDefAndScriptFailure2(lines, 'E1018:', 'E46:', 3) enddef def Test_for_loop_script_var() *** ../vim-8.2.2759/src/version.c 2021-04-13 20:53:09.846201149 +0200 --- src/version.c 2021-04-13 21:14:18.864756079 +0200 *************** *** 752,753 **** --- 752,755 ---- { /* Add new patch number below this line */ + /**/ + 2760, /**/ -- From "know your smileys": :-| :-| Deja' vu! /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///