Patch 8.2.2311
Problem:    Vim9: cannot assign to a variable that shadows a command modifier.
Solution:   Check for assignment after possible command modifier.
            (closes #7632)
Files:      src/vim9compile.c, src/ex_docmd.c,
            src/testdir/test_vim9_assign.vim


*** ../vim-8.2.2310/src/vim9compile.c   2021-01-07 19:23:04.966566919 +0100
--- src/vim9compile.c   2021-01-07 22:02:33.588205264 +0100
***************
*** 6217,6222 ****
--- 6217,6293 ----
  }
  
  /*
+  * Check for an assignment at "eap->cmd", compile it if found.
+  * Return NOTDONE if there is none, FAIL for failure, OK if done.
+  */
+     static int
+ may_compile_assignment(exarg_T *eap, char_u **line, cctx_T *cctx)
+ {
+     char_u  *pskip;
+     char_u  *p;
+ 
+     // Assuming the command starts with a variable or function name,
+     // find what follows.
+     // Skip over "var.member", "var[idx]" and the like.
+     // Also "&opt = val", "$ENV = val" and "@r = val".
+     pskip = (*eap->cmd == '&' || *eap->cmd == '$' || *eap->cmd == '@')
+                                                ? eap->cmd + 1 : eap->cmd;
+     p = to_name_end(pskip, TRUE);
+     if (p > eap->cmd && *p != NUL)
+     {
+       char_u *var_end;
+       int     oplen;
+       int     heredoc;
+ 
+       if (eap->cmd[0] == '@')
+           var_end = eap->cmd + 2;
+       else
+           var_end = find_name_end(pskip, NULL, NULL,
+                                       FNE_CHECK_START | FNE_INCL_BR);
+       oplen = assignment_len(skipwhite(var_end), &heredoc);
+       if (oplen > 0)
+       {
+           size_t len = p - eap->cmd;
+ 
+           // Recognize an assignment if we recognize the variable
+           // name:
+           // "g:var = expr"
+           // "local = expr"  where "local" is a local var.
+           // "script = expr"  where "script" is a script-local var.
+           // "import = expr"  where "import" is an imported var
+           // "&opt = expr"
+           // "$ENV = expr"
+           // "@r = expr"
+           if (*eap->cmd == '&'
+                   || *eap->cmd == '$'
+                   || *eap->cmd == '@'
+                   || ((len) > 2 && eap->cmd[1] == ':')
+                   || lookup_local(eap->cmd, len, NULL, cctx) == OK
+                   || arg_exists(eap->cmd, len, NULL, NULL, NULL, cctx) == OK
+                   || script_var_exists(eap->cmd, len, FALSE, cctx) == OK
+                   || find_imported(eap->cmd, len, cctx) != NULL)
+           {
+               *line = compile_assignment(eap->cmd, eap, CMD_SIZE, cctx);
+               if (*line == NULL || *line == eap->cmd)
+                   return FAIL;
+               return OK;
+           }
+       }
+     }
+ 
+     if (*eap->cmd == '[')
+     {
+       // [var, var] = expr
+       *line = compile_assignment(eap->cmd, eap, CMD_SIZE, cctx);
+       if (*line == NULL)
+           return FAIL;
+       if (*line != eap->cmd)
+           return OK;
+     }
+     return NOTDONE;
+ }
+ 
+ /*
   * Check if "name" can be "unlet".
   */
      int
***************
*** 7838,7905 ****
  
        if (!starts_with_colon)
        {
!           char_u *pskip;
  
!           // Assuming the command starts with a variable or function name,
!           // find what follows.
!           // Skip over "var.member", "var[idx]" and the like.
!           // Also "&opt = val", "$ENV = val" and "@r = val".
!           pskip = (*ea.cmd == '&' || *ea.cmd == '$' || *ea.cmd == '@')
!                                                        ? ea.cmd + 1 : ea.cmd;
!           p = to_name_end(pskip, TRUE);
!           if (p > ea.cmd && *p != NUL)
!           {
!               char_u *var_end;
!               int     oplen;
!               int     heredoc;
! 
!               if (ea.cmd[0] == '@')
!                   var_end = ea.cmd + 2;
!               else
!                   var_end = find_name_end(pskip, NULL, NULL,
!                                               FNE_CHECK_START | FNE_INCL_BR);
!               oplen = assignment_len(skipwhite(var_end), &heredoc);
!               if (oplen > 0)
!               {
!                   size_t len = p - ea.cmd;
! 
!                   // Recognize an assignment if we recognize the variable
!                   // name:
!                   // "g:var = expr"
!                   // "local = expr"  where "local" is a local var.
!                   // "script = expr"  where "script" is a script-local var.
!                   // "import = expr"  where "import" is an imported var
!                   // "&opt = expr"
!                   // "$ENV = expr"
!                   // "@r = expr"
!                   if (*ea.cmd == '&'
!                           || *ea.cmd == '$'
!                           || *ea.cmd == '@'
!                           || ((len) > 2 && ea.cmd[1] == ':')
!                           || lookup_local(ea.cmd, len, NULL, &cctx) == OK
!                           || arg_exists(ea.cmd, len, NULL, NULL,
!                                                            NULL, &cctx) == OK
!                           || script_var_exists(ea.cmd, len,
!                                                           FALSE, &cctx) == OK
!                           || find_imported(ea.cmd, len, &cctx) != NULL)
!                   {
!                       line = compile_assignment(ea.cmd, &ea, CMD_SIZE, &cctx);
!                       if (line == NULL || line == ea.cmd)
!                           goto erret;
!                       goto nextline;
!                   }
!               }
!           }
! 
!           if (*ea.cmd == '[')
!           {
!               // [var, var] = expr
!               line = compile_assignment(ea.cmd, &ea, CMD_SIZE, &cctx);
!               if (line == NULL)
!                   goto erret;
!               if (line != ea.cmd)
!                   goto nextline;
!           }
        }
  
        /*
--- 7909,7922 ----
  
        if (!starts_with_colon)
        {
!           int     assign;
  
!           // Check for assignment after command modifiers.
!           assign = may_compile_assignment(&ea, &line, &cctx);
!           if (assign == OK)
!               goto nextline;
!           if (assign == FAIL)
!               goto erret;
        }
  
        /*
*** ../vim-8.2.2310/src/ex_docmd.c      2021-01-04 16:15:55.066084896 +0100
--- src/ex_docmd.c      2021-01-07 21:56:15.173041913 +0100
***************
*** 2738,2743 ****
--- 2738,2762 ----
        }
  
        p = skip_range(eap->cmd, TRUE, NULL);
+ 
+       // In Vim9 script a variable can shadow a command modifier:
+       //   verbose = 123
+       //   verbose += 123
+       //   silent! verbose = func()
+       //   verbose.member = 2
+       //   verbose[expr] = 2
+       if (in_vim9script())
+       {
+           char_u *s;
+ 
+           for (s = p; ASCII_ISALPHA(*s); ++s)
+               ;
+           s = skipwhite(s);
+           if (vim_strchr((char_u *)".[=", *s) != NULL
+                                                || (*s != NUL && s[1] == '='))
+               break;
+       }
+ 
        switch (*p)
        {
            // When adding an entry, also modify cmd_exists().
*** ../vim-8.2.2310/src/testdir/test_vim9_assign.vim    2021-01-07 
19:23:04.966566919 +0100
--- src/testdir/test_vim9_assign.vim    2021-01-07 21:56:35.244998244 +0100
***************
*** 1464,1468 ****
--- 1464,1489 ----
    assert_equal('', $ENVVAR)
  enddef
  
+ def Test_assign_command_modifier()
+   var lines =<< trim END
+     var verbose = 0
+     verbose = 1
+     assert_equal(1, verbose)
+     silent verbose = 2
+     assert_equal(2, verbose)
+     silent verbose += 2
+     assert_equal(4, verbose)
+     silent verbose -= 1
+     assert_equal(3, verbose)
+ 
+     var topleft = {one: 1}
+     sandbox topleft.one = 3
+     assert_equal({one: 3}, topleft)
+     leftabove topleft[' '] = 4
+     assert_equal({one: 3, ' ': 4}, topleft)
+   END
+   CheckDefAndScriptSuccess(lines)
+ enddef
+ 
  
  " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
*** ../vim-8.2.2310/src/version.c       2021-01-07 20:23:29.846515289 +0100
--- src/version.c       2021-01-07 21:38:38.395022245 +0100
***************
*** 752,753 ****
--- 752,755 ----
  {   /* Add new patch number below this line */
+ /**/
+     2311,
  /**/

-- 
hundred-and-one symptoms of being an internet addict:
104. When people ask about the Presidential Election you ask "Which country?"

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\  an exciting new programming language -- http://www.Zimbu.org        ///
 \\\            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 [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/202101072104.107L4TVJ656635%40masaka.moolenaar.net.

Raspunde prin e-mail lui