To: vim_dev@googlegroups.com Subject: Patch 8.2.1813 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ 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 + s:dict['a'] = ['x'] + END + CheckScriptFailure(lines, 'E1012: Type mismatch; expected string but got list', 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 -- Bram@Moolenaar.net -- 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 ///