Patch 8.2.1813
Problem:    Vim9: can assign wrong type to script dict. (Christian J.  Robinson)
Solution:   Check the type if known.
Files:      src/structs.h, src/eval.c, src/vim9script.c,
            src/proto/vim9script.pro, src/proto/evalvars.pro,
            src/testdir/test_vim9_script.vim


*** ../vim-8.2.1812/src/structs.h       2020-10-03 22:51:42.890813408 +0200
--- src/structs.h       2020-10-08 20:43:44.200016806 +0200
***************
*** 4055,4060 ****
--- 4055,4061 ----
      dict_T    *ll_dict;       // The Dictionary or NULL
      dictitem_T        *ll_di;         // The dictitem or NULL
      char_u    *ll_newkey;     // New key for Dict in alloc. mem or NULL.
+     type_T    *ll_valtype;    // type expected for the value or NULL
      blob_T    *ll_blob;       // The Blob or NULL
  } lval_T;
  
*** ../vim-8.2.1812/src/eval.c  2020-10-04 16:06:00.513884339 +0200
--- src/eval.c  2020-10-08 21:11:21.356457068 +0200
***************
*** 887,892 ****
--- 887,903 ----
            return NULL;
        }
  
+       if (in_vim9script() && lp->ll_valtype == NULL
+               && lp->ll_tv == &v->di_tv
+               && ht != NULL && ht == get_script_local_ht())
+       {
+           svar_T  *sv = find_typval_in_script(lp->ll_tv);
+ 
+           // Vim9 script local variable: get the type
+           if (sv != NULL)
+               lp->ll_valtype = sv->sv_type;
+       }
+ 
        len = -1;
        if (*p == '.')
        {
***************
*** 1037,1042 ****
--- 1048,1057 ----
                }
            }
  
+           if (lp->ll_valtype != NULL)
+               // use the type of the member
+               lp->ll_valtype = lp->ll_valtype->tt_member;
+ 
            if (lp->ll_di == NULL)
            {
                // Can't add "v:" or "a:" variable.
***************
*** 1148,1153 ****
--- 1163,1172 ----
                return NULL;
            }
  
+           if (lp->ll_valtype != NULL)
+               // use the type of the member
+               lp->ll_valtype = lp->ll_valtype->tt_member;
+ 
            /*
             * May need to find the item or absolute index for the second
             * index of a range.
***************
*** 1383,1388 ****
--- 1402,1412 ----
            emsg(_("E996: Cannot lock a list or dict"));
            return;
        }
+ 
+       if (lp->ll_valtype != NULL
+                       && check_typval_type(lp->ll_valtype, rettv, 0) == FAIL)
+           return;
+ 
        if (lp->ll_newkey != NULL)
        {
            if (op != NULL && *op != '=')
*** ../vim-8.2.1812/src/vim9script.c    2020-09-26 15:08:52.881779910 +0200
--- src/vim9script.c    2020-10-08 20:54:43.898813084 +0200
***************
*** 565,582 ****
  }
  
  /*
!  * Check if the type of script variable "dest" allows assigning "value".
!  * If needed convert "value" to a bool.
   */
!     int
! check_script_var_type(typval_T *dest, typval_T *value, char_u *name)
  {
      scriptitem_T    *si = SCRIPT_ITEM(current_sctx.sc_sid);
      int                   idx;
  
      if (si->sn_version != SCRIPT_VERSION_VIM9)
        // legacy script doesn't store variable types
!       return OK;
  
      // Find the svar_T in sn_var_vals.
      for (idx = 0; idx < si->sn_var_vals.ga_len; ++idx)
--- 565,582 ----
  }
  
  /*
!  * Find the script-local variable that links to "dest".
!  * Returns NULL if not found.
   */
!     svar_T *
! find_typval_in_script(typval_T *dest)
  {
      scriptitem_T    *si = SCRIPT_ITEM(current_sctx.sc_sid);
      int                   idx;
  
      if (si->sn_version != SCRIPT_VERSION_VIM9)
        // legacy script doesn't store variable types
!       return NULL;
  
      // Find the svar_T in sn_var_vals.
      for (idx = 0; idx < si->sn_var_vals.ga_len; ++idx)
***************
*** 584,611 ****
        svar_T    *sv = ((svar_T *)si->sn_var_vals.ga_data) + idx;
  
        if (sv->sv_tv == dest)
        {
!           int     ret;
  
!           if (sv->sv_const)
!           {
!               semsg(_(e_readonlyvar), name);
!               return FAIL;
!           }
!           ret = check_typval_type(sv->sv_type, value, 0);
!           if (ret == OK && need_convert_to_bool(sv->sv_type, value))
!           {
!               int     val = tv2bool(value);
! 
!               clear_tv(value);
!               value->v_type = VAR_BOOL;
!               value->v_lock = 0;
!               value->vval.v_number = val ? VVAL_TRUE : VVAL_FALSE;
!           }
!           return ret;
        }
      }
!     iemsg("check_script_var_type(): not found");
      return OK; // not really
  }
  
--- 584,625 ----
        svar_T    *sv = ((svar_T *)si->sn_var_vals.ga_data) + idx;
  
        if (sv->sv_tv == dest)
+           return sv;
+     }
+     iemsg("check_script_var_type(): not found");
+     return NULL;
+ }
+ 
+ /*
+  * Check if the type of script variable "dest" allows assigning "value".
+  * If needed convert "value" to a bool.
+  */
+     int
+ check_script_var_type(typval_T *dest, typval_T *value, char_u *name)
+ {
+     svar_T  *sv = find_typval_in_script(dest);
+     int           ret;
+ 
+     if (sv != NULL)
+     {
+       if (sv->sv_const)
+       {
+           semsg(_(e_readonlyvar), name);
+           return FAIL;
+       }
+       ret = check_typval_type(sv->sv_type, value, 0);
+       if (ret == OK && need_convert_to_bool(sv->sv_type, value))
        {
!           int val = tv2bool(value);
  
!           clear_tv(value);
!           value->v_type = VAR_BOOL;
!           value->v_lock = 0;
!           value->vval.v_number = val ? VVAL_TRUE : VVAL_FALSE;
        }
+       return ret;
      }
! 
      return OK; // not really
  }
  
*** ../vim-8.2.1812/src/proto/vim9script.pro    2020-07-28 20:06:46.115280293 
+0200
--- src/proto/vim9script.pro    2020-10-08 20:58:31.962304124 +0200
***************
*** 8,12 ****
--- 8,13 ----
  int find_exported(int sid, char_u *name, ufunc_T **ufunc, type_T **type);
  char_u *handle_import(char_u *arg_start, garray_T *gap, int import_sid, 
evalarg_T *evalarg, void *cctx);
  char_u *vim9_declare_scriptvar(exarg_T *eap, char_u *arg);
+ svar_T *find_typval_in_script(typval_T *dest);
  int check_script_var_type(typval_T *dest, typval_T *value, char_u *name);
  /* vim: set ft=c : */
*** ../vim-8.2.1812/src/proto/evalvars.pro      2020-09-26 15:08:52.881779910 
+0200
--- src/proto/evalvars.pro      2020-10-08 20:59:09.030219067 +0200
***************
*** 58,63 ****
--- 58,64 ----
  void check_vars(char_u *name, int len);
  dictitem_T *find_var(char_u *name, hashtab_T **htp, int no_autoload);
  dictitem_T *find_var_in_ht(hashtab_T *ht, int htname, char_u *varname, int 
no_autoload);
+ hashtab_T *get_script_local_ht(void);
  void *lookup_scriptvar(char_u *name, size_t len, cctx_T *dummy);
  hashtab_T *find_var_ht(char_u *name, char_u **varname);
  char_u *get_var_value(char_u *name);
*** ../vim-8.2.1812/src/testdir/test_vim9_script.vim    2020-10-04 
16:06:00.513884339 +0200
--- src/testdir/test_vim9_script.vim    2020-10-08 21:15:39.751793995 +0200
***************
*** 145,150 ****
--- 145,159 ----
    CheckDefFailure(['var Ref: string', 'var res = Ref()'], 'E1085:')
  enddef
  
+ def Test_script_wrong_type()
+   var lines =<< trim END
+       vim9script
+       var s:dict: dict<string>
+       s:dict['a'] = ['x']
+   END
+   CheckScriptFailure(lines, 'E1012: Type mismatch; expected string but got 
list<string>', 3)
+ enddef
+ 
  def Test_const()
    CheckDefFailure(['final name = 234', 'name = 99'], 'E1018:')
    CheckDefFailure(['final one = 234', 'var one = 99'], 'E1017:')
*** ../vim-8.2.1812/src/version.c       2020-10-07 19:08:00.013793470 +0200
--- src/version.c       2020-10-08 21:16:16.847699389 +0200
***************
*** 752,753 ****
--- 752,755 ----
  {   /* Add new patch number below this line */
+ /**/
+     1813,
  /**/

-- 
The real
trick is
this: to
keep the
lines as
short as
possible
and keep
the size
the same
yet free
from the
need for
hyphena-
Dammit!!  (Matthew Winn)

 /// 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/202010081917.098JHjAS3275508%40masaka.moolenaar.net.

Raspunde prin e-mail lui