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<dict<any>> = [{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 -- b...@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    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to vim_dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/202104131948.13DJmfGG1062990%40masaka.moolenaar.net.

Reply via email to