Patch 8.2.0201
Problem:    Cannot assign to an imported variable.
Solution:   Make it work.
Files:      src/evalvars.c, src/vim9compile.c, src/proto/vim9compile.pro,
            src/userfunc.c, src/testdir/test_vim9_script.vim


*** ../vim-8.2.0200/src/evalvars.c      2020-02-02 22:24:00.624827188 +0100
--- src/evalvars.c      2020-02-02 23:01:32.498917653 +0100
***************
*** 2296,2302 ****
  
      if (tv == NULL && current_sctx.sc_version == SCRIPT_VERSION_VIM9)
      {
!       imported_T *import = find_imported(name, NULL);
  
        // imported variable from another script
        if (import != NULL)
--- 2296,2302 ----
  
      if (tv == NULL && current_sctx.sc_version == SCRIPT_VERSION_VIM9)
      {
!       imported_T *import = find_imported(name, 0, NULL);
  
        // imported variable from another script
        if (import != NULL)
***************
*** 2472,2478 ****
      res = HASHITEM_EMPTY(hi) ? -1 : 1;
  
      // if not script-local, then perhaps imported
!     if (res == -1 && find_imported(p, NULL) != NULL)
        res = 1;
  
      if (p != buffer)
--- 2472,2478 ----
      res = HASHITEM_EMPTY(hi) ? -1 : 1;
  
      // if not script-local, then perhaps imported
!     if (res == -1 && find_imported(p, 0, NULL) != NULL)
        res = 1;
  
      if (p != buffer)
*** ../vim-8.2.0200/src/vim9compile.c   2020-02-02 22:24:00.624827188 +0100
--- src/vim9compile.c   2020-02-03 20:50:05.549112994 +0100
***************
*** 1467,1473 ****
   * Find "name" in imported items of the current script/
   */
      imported_T *
! find_imported(char_u *name, cctx_T *cctx)
  {
      scriptitem_T    *si = SCRIPT_ITEM(current_sctx.sc_sid);
      int                   idx;
--- 1467,1473 ----
   * Find "name" in imported items of the current script/
   */
      imported_T *
! find_imported(char_u *name, size_t len, cctx_T *cctx)
  {
      scriptitem_T    *si = SCRIPT_ITEM(current_sctx.sc_sid);
      int                   idx;
***************
*** 1478,1484 ****
            imported_T *import = ((imported_T *)cctx->ctx_imports.ga_data)
                                                                         + idx;
  
!           if (STRCMP(name, import->imp_name) == 0)
                return import;
        }
  
--- 1478,1486 ----
            imported_T *import = ((imported_T *)cctx->ctx_imports.ga_data)
                                                                         + idx;
  
!           if (len == 0 ? STRCMP(name, import->imp_name) == 0
!                        : STRLEN(import->imp_name) == len
!                                 && STRNCMP(name, import->imp_name, len) == 0)
                return import;
        }
  
***************
*** 1486,1492 ****
      {
        imported_T *import = ((imported_T *)si->sn_imports.ga_data) + idx;
  
!       if (STRCMP(name, import->imp_name) == 0)
            return import;
      }
      return NULL;
--- 1488,1496 ----
      {
        imported_T *import = ((imported_T *)si->sn_imports.ga_data) + idx;
  
!       if (len == 0 ? STRCMP(name, import->imp_name) == 0
!                    : STRLEN(import->imp_name) == len
!                                 && STRNCMP(name, import->imp_name, len) == 0)
            return import;
      }
      return NULL;
***************
*** 1517,1523 ****
        return OK;
      }
  
!     import = find_imported(name, cctx);
      if (import != NULL)
      {
        // TODO: check this is a variable, not a function
--- 1521,1527 ----
        return OK;
      }
  
!     import = find_imported(name, 0, cctx);
      if (import != NULL)
      {
        // TODO: check this is a variable, not a function
***************
*** 3071,3076 ****
--- 3075,3090 ----
                                                             [cctx->ctx_lnum]);
  }
  
+ typedef enum {
+     dest_local,
+     dest_option,
+     dest_env,
+     dest_global,
+     dest_vimvar,
+     dest_script,
+     dest_reg,
+ } assign_dest_T;
+ 
  /*
   * compile "let var [= expr]", "const var = expr" and "var = expr"
   * "arg" points to "var".
***************
*** 3086,3099 ****
      garray_T  *instr = &cctx->ctx_instr;
      int               idx = -1;
      char_u    *op;
-     int               option = FALSE;
      int               opt_type;
      int               opt_flags = 0;
-     int               global = FALSE;
-     int               env = FALSE;
-     int               reg = FALSE;
      int               vimvaridx = -1;
-     int               script = FALSE;
      int               oplen = 0;
      int               heredoc = FALSE;
      type_T    *type;
--- 3100,3109 ----
      garray_T  *instr = &cctx->ctx_instr;
      int               idx = -1;
      char_u    *op;
      int               opt_type;
+     assign_dest_T dest = dest_local;
      int               opt_flags = 0;
      int               vimvaridx = -1;
      int               oplen = 0;
      int               heredoc = FALSE;
      type_T    *type;
***************
*** 3125,3131 ****
        long        numval;
        char_u      *stringval = NULL;
  
!       option = TRUE;
        if (cmdidx == CMD_const)
        {
            emsg(_(e_const_option));
--- 3135,3141 ----
        long        numval;
        char_u      *stringval = NULL;
  
!       dest = dest_option;
        if (cmdidx == CMD_const)
        {
            emsg(_(e_const_option));
***************
*** 3159,3165 ****
      }
      else if (*arg == '$')
      {
!       env = TRUE;
        if (is_decl)
        {
            semsg(_("E1065: Cannot declare an environment variable: %s"), name);
--- 3169,3175 ----
      }
      else if (*arg == '$')
      {
!       dest = dest_env;
        if (is_decl)
        {
            semsg(_("E1065: Cannot declare an environment variable: %s"), name);
***************
*** 3173,3179 ****
            emsg_invreg(arg[1]);
            return FAIL;
        }
!       reg = TRUE;
        if (is_decl)
        {
            semsg(_("E1066: Cannot declare a register: %s"), name);
--- 3183,3189 ----
            emsg_invreg(arg[1]);
            return FAIL;
        }
!       dest = dest_reg;
        if (is_decl)
        {
            semsg(_("E1066: Cannot declare a register: %s"), name);
***************
*** 3182,3188 ****
      }
      else if (STRNCMP(arg, "g:", 2) == 0)
      {
!       global = TRUE;
        if (is_decl)
        {
            semsg(_("E1016: Cannot declare a global variable: %s"), name);
--- 3192,3198 ----
      }
      else if (STRNCMP(arg, "g:", 2) == 0)
      {
!       dest = dest_global;
        if (is_decl)
        {
            semsg(_("E1016: Cannot declare a global variable: %s"), name);
***************
*** 3197,3202 ****
--- 3207,3213 ----
            semsg(_(e_var_notfound), arg);
            goto theend;
        }
+       dest = dest_vimvar;
        if (is_decl)
        {
            semsg(_("E1064: Cannot declare a v: variable: %s"), name);
***************
*** 3232,3240 ****
        }
        else if ((STRNCMP(arg, "s:", 2) == 0
                    ? lookup_script(arg + 2, varlen - 2)
!                   : lookup_script(arg, varlen)) == OK)
        {
!           script = TRUE;
            if (is_decl)
            {
                semsg(_("E1054: Variable already declared in the script: %s"),
--- 3243,3252 ----
        }
        else if ((STRNCMP(arg, "s:", 2) == 0
                    ? lookup_script(arg + 2, varlen - 2)
!                   : lookup_script(arg, varlen)) == OK
!                                  || find_imported(arg, varlen, cctx) != NULL)
        {
!           dest = dest_script;
            if (is_decl)
            {
                semsg(_("E1054: Variable already declared in the script: %s"),
***************
*** 3244,3250 ****
        }
      }
  
!     if (!option)
      {
        if (is_decl && *p == ':')
        {
--- 3256,3262 ----
        }
      }
  
!     if (dest != dest_option)
      {
        if (is_decl && *p == ':')
        {
***************
*** 3279,3293 ****
        semsg(_(e_white_both), buf);
      }
  
!     if (oplen == 3 && !heredoc && !global && type->tt_type != VAR_STRING
!                                              && type->tt_type != VAR_UNKNOWN)
      {
        emsg("E1019: Can only concatenate to string");
        goto theend;
      }
  
      // +=, /=, etc. require an existing variable
!     if (idx < 0 && !global && !env && !reg && !option)
      {
        if (oplen > 1 && !heredoc)
        {
--- 3291,3305 ----
        semsg(_(e_white_both), buf);
      }
  
!     if (oplen == 3 && !heredoc && dest != dest_global
!           && type->tt_type != VAR_STRING && type->tt_type != VAR_UNKNOWN)
      {
        emsg("E1019: Can only concatenate to string");
        goto theend;
      }
  
      // +=, /=, etc. require an existing variable
!     if (idx < 0 && dest == dest_local)
      {
        if (oplen > 1 && !heredoc)
        {
***************
*** 3328,3347 ****
        // for "+=", "*=", "..=" etc. first load the current value
        if (*op != '=')
        {
!           if (option)
!               // TODO: check the option exists
!               generate_LOAD(cctx, ISN_LOADOPT, 0, name + 1, type);
!           else if (global)
!               generate_LOAD(cctx, ISN_LOADG, 0, name + 2, type);
!           else if (env)
!               // Include $ in the name here
!               generate_LOAD(cctx, ISN_LOADENV, 0, name, type);
!           else if (reg)
!               generate_LOAD(cctx, ISN_LOADREG, arg[1], NULL, &t_string);
!           else if (vimvaridx >= 0)
!               generate_LOADV(cctx, name + 2, TRUE);
!           else
!               generate_LOAD(cctx, ISN_LOAD, idx, NULL, type);
        }
  
        // compile the expression
--- 3340,3371 ----
        // for "+=", "*=", "..=" etc. first load the current value
        if (*op != '=')
        {
!           switch (dest)
!           {
!               case dest_option:
!                   // TODO: check the option exists
!                   generate_LOAD(cctx, ISN_LOADOPT, 0, name + 1, type);
!                   break;
!               case dest_global:
!                   generate_LOAD(cctx, ISN_LOADG, 0, name + 2, type);
!                   break;
!               case dest_script:
!                   compile_load_scriptvar(cctx, name);
!                   break;
!               case dest_env:
!                   // Include $ in the name here
!                   generate_LOAD(cctx, ISN_LOADENV, 0, name, type);
!                   break;
!               case dest_reg:
!                   generate_LOAD(cctx, ISN_LOADREG, arg[1], NULL, &t_string);
!                   break;
!               case dest_vimvar:
!                   generate_LOADV(cctx, name + 2, TRUE);
!                   break;
!               case dest_local:
!                   generate_LOAD(cctx, ISN_LOAD, idx, NULL, type);
!                   break;
!           }
        }
  
        // compile the expression
***************
*** 3377,3383 ****
        emsg(_("E1021: const requires a value"));
        goto theend;
      }
!     else if (!has_type || option)
      {
        emsg(_("E1022: type or initialization required"));
        goto theend;
--- 3401,3407 ----
        emsg(_("E1021: const requires a value"));
        goto theend;
      }
!     else if (!has_type || dest == dest_option)
      {
        emsg(_("E1022: type or initialization required"));
        goto theend;
***************
*** 3427,3475 ****
        }
      }
  
!     if (option)
!       generate_STOREOPT(cctx, name + 1, opt_flags);
!     else if (global)
!       // include g: with the name, easier to execute that way
!       generate_STORE(cctx, ISN_STOREG, 0, name);
!     else if (env)
!       generate_STORE(cctx, ISN_STOREENV, 0, name + 1);
!     else if (reg)
!       generate_STORE(cctx, ISN_STOREREG, name[1], NULL);
!     else if (vimvaridx >= 0)
!       generate_STORE(cctx, ISN_STOREV, vimvaridx, NULL);
!     else if (script)
      {
!       char_u *rawname = name + (name[1] == ':' ? 2 : 0);
  
!       idx = get_script_item_idx(current_sctx.sc_sid, rawname, TRUE);
!       // TODO: specific type
!       if (idx < 0)
!           generate_OLDSCRIPT(cctx, ISN_STORES, rawname,
!                                                 current_sctx.sc_sid, &t_any);
!       else
!           generate_VIM9SCRIPT(cctx, ISN_STORESCRIPT,
!                                            current_sctx.sc_sid, idx, &t_any);
!     }
!     else
!     {
!       isn_T *isn = ((isn_T *)instr->ga_data) + instr->ga_len - 1;
  
!       // optimization: turn "var = 123" from ISN_PUSHNR + ISN_STORE into
!       // ISN_STORENR
!       if (instr->ga_len == instr_count + 1 && isn->isn_type == ISN_PUSHNR)
!       {
!           varnumber_T val = isn->isn_arg.number;
!           garray_T    *stack = &cctx->ctx_type_stack;
  
!           isn->isn_type = ISN_STORENR;
!           isn->isn_arg.storenr.str_idx = idx;
!           isn->isn_arg.storenr.str_val = val;
!           if (stack->ga_len > 0)
!               --stack->ga_len;
!       }
!       else
!           generate_STORE(cctx, ISN_STORE, idx, NULL);
      }
      ret = p;
  
--- 3451,3518 ----
        }
      }
  
!     switch (dest)
      {
!       case dest_option:
!           generate_STOREOPT(cctx, name + 1, opt_flags);
!           break;
!       case dest_global:
!           // include g: with the name, easier to execute that way
!           generate_STORE(cctx, ISN_STOREG, 0, name);
!           break;
!       case dest_env:
!           generate_STORE(cctx, ISN_STOREENV, 0, name + 1);
!           break;
!       case dest_reg:
!           generate_STORE(cctx, ISN_STOREREG, name[1], NULL);
!           break;
!       case dest_vimvar:
!           generate_STORE(cctx, ISN_STOREV, vimvaridx, NULL);
!           break;
!       case dest_script:
!           {
!               char_u      *rawname = name + (name[1] == ':' ? 2 : 0);
!               imported_T  *import = NULL;
!               int         sid = current_sctx.sc_sid;
  
!               if (name[1] != ':')
!               {
!                   import = find_imported(name, 0, cctx);
!                   if (import != NULL)
!                       sid = import->imp_sid;
!               }
  
!               idx = get_script_item_idx(sid, rawname, TRUE);
!               // TODO: specific type
!               if (idx < 0)
!                   generate_OLDSCRIPT(cctx, ISN_STORES, rawname, sid, &t_any);
!               else
!                   generate_VIM9SCRIPT(cctx, ISN_STORESCRIPT,
!                                                            sid, idx, &t_any);
!           }
!           break;
!       case dest_local:
!           {
!               isn_T *isn = ((isn_T *)instr->ga_data) + instr->ga_len - 1;
  
!               // optimization: turn "var = 123" from ISN_PUSHNR + ISN_STORE
!               // into ISN_STORENR
!               if (instr->ga_len == instr_count + 1
!                                               && isn->isn_type == ISN_PUSHNR)
!               {
!                   varnumber_T val = isn->isn_arg.number;
!                   garray_T    *stack = &cctx->ctx_type_stack;
! 
!                   isn->isn_type = ISN_STORENR;
!                   isn->isn_arg.storenr.str_idx = idx;
!                   isn->isn_arg.storenr.str_val = val;
!                   if (stack->ga_len > 0)
!                       --stack->ga_len;
!               }
!               else
!                   generate_STORE(cctx, ISN_STORE, idx, NULL);
!           }
!           break;
      }
      ret = p;
  
***************
*** 4619,4625 ****
  
            // "funcname(" is always a function call.
            // "varname[]" is an expression.
-           // "g:varname" is an expression.
            // "varname->expr" is an expression.
            if (*p == '('
                    || *p == '['
--- 4662,4667 ----
***************
*** 4643,4649 ****
                        || *ea.cmd == '@'
                        || ((p - ea.cmd) > 2 && ea.cmd[1] == ':')
                        || lookup_local(ea.cmd, p - ea.cmd, &cctx) >= 0
!                       || lookup_script(ea.cmd, p - ea.cmd) == OK)
                {
                    line = compile_assignment(ea.cmd, &ea, CMD_SIZE, &cctx);
                    if (line == NULL)
--- 4685,4692 ----
                        || *ea.cmd == '@'
                        || ((p - ea.cmd) > 2 && ea.cmd[1] == ':')
                        || lookup_local(ea.cmd, p - ea.cmd, &cctx) >= 0
!                       || lookup_script(ea.cmd, p - ea.cmd) == OK
!                       || find_imported(ea.cmd, p - ea.cmd, &cctx) != NULL)
                {
                    line = compile_assignment(ea.cmd, &ea, CMD_SIZE, &cctx);
                    if (line == NULL)
*** ../vim-8.2.0200/src/proto/vim9compile.pro   2020-01-26 15:52:33.023833239 
+0100
--- src/proto/vim9compile.pro   2020-02-02 23:01:55.478792829 +0100
***************
*** 4,10 ****
  char *vartype_name(vartype_T type);
  char *type_name(type_T *type, char **tofree);
  int get_script_item_idx(int sid, char_u *name, int check_writable);
! imported_T *find_imported(char_u *name, cctx_T *cctx);
  char_u *to_name_end(char_u *arg);
  char_u *to_name_const_end(char_u *arg);
  int assignment_len(char_u *p, int *heredoc);
--- 4,10 ----
  char *vartype_name(vartype_T type);
  char *type_name(type_T *type, char **tofree);
  int get_script_item_idx(int sid, char_u *name, int check_writable);
! imported_T *find_imported(char_u *name, size_t len, cctx_T *cctx);
  char_u *to_name_end(char_u *arg);
  char_u *to_name_const_end(char_u *arg);
  int assignment_len(char_u *p, int *heredoc);
*** ../vim-8.2.0200/src/userfunc.c      2020-02-02 17:22:23.438043236 +0100
--- src/userfunc.c      2020-02-02 23:01:48.194832260 +0100
***************
*** 678,684 ****
            return func;
  
        // Find imported funcion before global one.
!       imported = find_imported(name, cctx);
        if (imported != NULL && imported->imp_funcname != NULL)
        {
            hi = hash_find(&func_hashtab, imported->imp_funcname);
--- 678,684 ----
            return func;
  
        // Find imported funcion before global one.
!       imported = find_imported(name, 0, cctx);
        if (imported != NULL && imported->imp_funcname != NULL)
        {
            hi = hash_find(&func_hashtab, imported->imp_funcname);
*** ../vim-8.2.0200/src/testdir/test_vim9_script.vim    2020-02-02 
22:24:00.624827188 +0100
--- src/testdir/test_vim9_script.vim    2020-02-03 20:35:45.627973293 +0100
***************
*** 320,328 ****
          \ 'import exported from "' .. escape(getcwd(), '\') .. 
'/Xexport_abs.vim"',
          \ 'def UseExported()',
          \ '  g:imported_abs = exported',
          \ 'enddef',
          \ 'UseExported()',
!         \ 'g:import_disassabled = execute("disass UseExported")',
          \ ]
    writefile(import_lines, 'Ximport_abs.vim')
    writefile(s:export_script_lines, 'Xexport_abs.vim')
--- 320,330 ----
          \ 'import exported from "' .. escape(getcwd(), '\') .. 
'/Xexport_abs.vim"',
          \ 'def UseExported()',
          \ '  g:imported_abs = exported',
+         \ '  exported = 8888',
+         \ '  g:imported_after = exported',
          \ 'enddef',
          \ 'UseExported()',
!         \ 'g:import_disassembled = execute("disass UseExported")',
          \ ]
    writefile(import_lines, 'Ximport_abs.vim')
    writefile(s:export_script_lines, 'Xexport_abs.vim')
***************
*** 330,341 ****
    source Ximport_abs.vim
  
    assert_equal(9876, g:imported_abs)
    assert_match('<SNR>\d\+_UseExported.*'
          \ .. 'g:imported_abs = exported.*'
          \ .. '0 LOADSCRIPT exported from .*Xexport_abs.vim.*'
!         \ .. '1 STOREG g:imported_abs', g:import_disassabled)
    unlet g:imported_abs
!   unlet g:import_disassabled
  
    delete('Ximport_abs.vim')
    delete('Xexport_abs.vim')
--- 332,350 ----
    source Ximport_abs.vim
  
    assert_equal(9876, g:imported_abs)
+   assert_equal(8888, g:imported_after)
    assert_match('<SNR>\d\+_UseExported.*'
          \ .. 'g:imported_abs = exported.*'
          \ .. '0 LOADSCRIPT exported from .*Xexport_abs.vim.*'
!         \ .. '1 STOREG g:imported_abs.*'
!         \ .. 'exported = 8888.*'
!         \ .. '3 STORESCRIPT exported in .*Xexport_abs.vim.*'
!         \ .. 'g:imported_after = exported.*'
!         \ .. '4 LOADSCRIPT exported from .*Xexport_abs.vim.*'
!         \ .. '5 STOREG g:imported_after.*'
!         \, g:import_disassembled)
    unlet g:imported_abs
!   unlet g:import_disassembled
  
    delete('Ximport_abs.vim')
    delete('Xexport_abs.vim')
*** ../vim-8.2.0200/src/version.c       2020-02-02 22:24:00.628827172 +0100
--- src/version.c       2020-02-03 20:50:32.225015557 +0100
***************
*** 744,745 ****
--- 744,747 ----
  {   /* Add new patch number below this line */
+ /**/
+     201,
  /**/

-- 
If Pacman had affected us as kids we'd be running around in dark rooms,
munching pills and listening to repetitive music.
                       -- Marcus Brigstocke

 /// 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/202002031951.013JpWRc017174%40masaka.moolenaar.net.

Raspunde prin e-mail lui