summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2020-10-08 21:16:42 +0200
committerBram Moolenaar <Bram@vim.org>2020-10-08 21:16:42 +0200
commit10c65860f83589e0ca2498393d3cfef1115b7fe8 (patch)
tree5c52d0ded7ae00e522bcff80afff0e20bfed2389
parent0876c78527469ddf50c23244566dd5bc35004307 (diff)
patch 8.2.1813: Vim9: can assign wrong type to script dictv8.2.1813
Problem: Vim9: can assign wrong type to script dict. (Christian J. Robinson) Solution: Check the type if known.
-rw-r--r--src/eval.c24
-rw-r--r--src/proto/evalvars.pro1
-rw-r--r--src/proto/vim9script.pro1
-rw-r--r--src/structs.h1
-rw-r--r--src/testdir/test_vim9_script.vim9
-rw-r--r--src/version.c2
-rw-r--r--src/vim9script.c60
7 files changed, 75 insertions, 23 deletions
diff --git a/src/eval.c b/src/eval.c
index 285558df8f..f7657b4a84 100644
--- 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 != '=')
diff --git a/src/proto/evalvars.pro b/src/proto/evalvars.pro
index 69655089ea..520fedd5ef 100644
--- a/src/proto/evalvars.pro
+++ b/src/proto/evalvars.pro
@@ -58,6 +58,7 @@ int eval_variable(char_u *name, int len, typval_T *rettv, dictitem_T **dip, int
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);
diff --git a/src/proto/vim9script.pro b/src/proto/vim9script.pro
index f8b12ee5de..a20b715bc3 100644
--- 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 : */
diff --git a/src/structs.h b/src/structs.h
index 86c6ef8992..e7b72de23c 100644
--- 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;
diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim
index 7fc522362d..02bc56b2fa 100644
--- 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:')
diff --git a/src/version.c b/src/version.c
index 1c8629dd80..7d62814d22 100644
--- 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,
diff --git a/src/vim9script.c b/src/vim9script.c
index 399c4a7b05..d9f103fbf5 100644
--- a/src/vim9script.c
+++ b/src/vim9script.c
@@ -565,18 +565,18 @@ vim9_declare_scriptvar(exarg_T *eap, char_u *arg)
}
/*
- * 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, typval_T *value, char_u *name)
svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data) + idx;
if (sv->sv_tv == dest)
- {
- int ret;
+ return sv;
+ }
+ iemsg("check_script_var_type(): not found");
+ return 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);
+/*
+ * 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;
- clear_tv(value);
- value->v_type = VAR_BOOL;
- value->v_lock = 0;
- value->vval.v_number = val ? VVAL_TRUE : VVAL_FALSE;
- }
- return 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;
}
- iemsg("check_script_var_type(): not found");
+
return OK; // not really
}