Mercurial > vim
changeset 22529:35ef9b0a81a3 v8.2.1813
patch 8.2.1813: Vim9: can assign wrong type to script dict
Commit: https://github.com/vim/vim/commit/10c65860f83589e0ca2498393d3cfef1115b7fe8
Author: Bram Moolenaar <Bram@vim.org>
Date: Thu Oct 8 21:16:42 2020 +0200
patch 8.2.1813: Vim9: can assign wrong type to script dict
Problem: Vim9: can assign wrong type to script dict. (Christian J. Robinson)
Solution: Check the type if known.
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Thu, 08 Oct 2020 21:30:03 +0200 |
parents | 61f656177bed |
children | 6a5fda3130af |
files | src/eval.c src/proto/evalvars.pro src/proto/vim9script.pro src/structs.h src/testdir/test_vim9_script.vim src/version.c src/vim9script.c |
diffstat | 7 files changed, 77 insertions(+), 25 deletions(-) [+] |
line wrap: on
line diff
--- a/src/eval.c +++ b/src/eval.c @@ -887,6 +887,17 @@ get_lval( 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,6 +1048,10 @@ get_lval( } } + 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,6 +1163,10 @@ get_lval( 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,6 +1402,11 @@ set_var_lval( 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 != '=')
--- a/src/proto/evalvars.pro +++ b/src/proto/evalvars.pro @@ -58,6 +58,7 @@ int eval_variable(char_u *name, int len, 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);
--- a/src/proto/vim9script.pro +++ b/src/proto/vim9script.pro @@ -8,5 +8,6 @@ void ex_import(exarg_T *eap); 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 : */
--- a/src/structs.h +++ b/src/structs.h @@ -4055,6 +4055,7 @@ typedef struct lval_S 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;
--- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -145,6 +145,15 @@ def Test_wrong_type() 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:')
--- a/src/version.c +++ b/src/version.c @@ -751,6 +751,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1813, +/**/ 1812, /**/ 1811,
--- a/src/vim9script.c +++ b/src/vim9script.c @@ -565,18 +565,18 @@ vim9_declare_scriptvar(exarg_T *eap, cha } /* - * Check if the type of script variable "dest" allows assigning "value". - * If needed convert "value" to a bool. + * Find the script-local variable that links to "dest". + * Returns NULL if not found. */ - int -check_script_var_type(typval_T *dest, typval_T *value, char_u *name) + 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 OK; + return NULL; // Find the svar_T in sn_var_vals. for (idx = 0; idx < si->sn_var_vals.ga_len; ++idx) @@ -584,28 +584,42 @@ check_script_var_type(typval_T *dest, ty 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; - } + 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 }