0
0
mirror of https://github.com/vim/vim.git synced 2025-09-29 04:34:16 -04:00

patch 8.2.2331: Vim9: wrong error when modifying dict declared with :final

Problem:    Vim9: wrong error when modifying dict declared with :final.
Solution:   Do not check for writable variable when an index follows.
            (closes #7657)
This commit is contained in:
Bram Moolenaar
2021-01-11 21:20:18 +01:00
parent 9e1d9e3473
commit 082517570d
7 changed files with 68 additions and 18 deletions

View File

@@ -2126,11 +2126,30 @@ free_locals(cctx_T *cctx)
ga_clear(&cctx->ctx_locals);
}
/*
* If "check_writable" is ASSIGN_CONST give an error if the variable was
* defined with :final or :const, if "check_writable" is ASSIGN_FINAL give an
* error if the variable was defined with :const.
*/
static int
check_item_writable(svar_T *sv, int check_writable, char_u *name)
{
if ((check_writable == ASSIGN_CONST && sv->sv_const != 0)
|| (check_writable == ASSIGN_FINAL
&& sv->sv_const == ASSIGN_CONST))
{
semsg(_(e_readonlyvar), name);
return FAIL;
}
return OK;
}
/*
* Find "name" in script-local items of script "sid".
* Pass "check_writable" to check_item_writable().
* Returns the index in "sn_var_vals" if found.
* If found but not in "sn_var_vals" returns -1.
* If not found returns -2.
* If not found or the variable is not writable returns -2.
*/
int
get_script_item_idx(int sid, char_u *name, int check_writable, cctx_T *cctx)
@@ -2151,8 +2170,8 @@ get_script_item_idx(int sid, char_u *name, int check_writable, cctx_T *cctx)
return -2;
idx = sav->sav_var_vals_idx;
sv = ((svar_T *)si->sn_var_vals.ga_data) + idx;
if (check_writable && sv->sv_const)
semsg(_(e_readonlyvar), name);
if (check_item_writable(sv, check_writable, name) == FAIL)
return -2;
return idx;
}
@@ -2168,8 +2187,8 @@ get_script_item_idx(int sid, char_u *name, int check_writable, cctx_T *cctx)
sv = ((svar_T *)si->sn_var_vals.ga_data) + idx;
if (sv->sv_tv == &di->di_tv)
{
if (check_writable && sv->sv_const)
semsg(_(e_readonlyvar), name);
if (check_item_writable(sv, check_writable, name) == FAIL)
return -2;
return idx;
}
}
@@ -2466,7 +2485,7 @@ compile_load_scriptvar(
if (!SCRIPT_ID_VALID(current_sctx.sc_sid))
return FAIL;
si = SCRIPT_ITEM(current_sctx.sc_sid);
idx = get_script_item_idx(current_sctx.sc_sid, name, FALSE, cctx);
idx = get_script_item_idx(current_sctx.sc_sid, name, 0, cctx);
if (idx == -1 || si->sn_version != SCRIPT_VERSION_VIM9)
{
// variable is not in sn_var_vals: old style script.
@@ -5475,6 +5494,11 @@ compile_lhs(
lhs->lhs_name = vim_strnsave(var_start, lhs->lhs_varlen);
if (lhs->lhs_name == NULL)
return FAIL;
if (lhs->lhs_dest_end > var_start + lhs->lhs_varlen)
// Something follows after the variable: "var[idx]" or "var.key".
lhs->lhs_has_index = TRUE;
if (heredoc)
lhs->lhs_type = &t_list_string;
else
@@ -5576,9 +5600,11 @@ compile_lhs(
lhs->lhs_scriptvar_sid = import->imp_sid;
if (SCRIPT_ID_VALID(lhs->lhs_scriptvar_sid))
{
// Check writable only when no index follows.
lhs->lhs_scriptvar_idx = get_script_item_idx(
lhs->lhs_scriptvar_sid,
rawname, TRUE, cctx);
lhs->lhs_scriptvar_sid, rawname,
lhs->lhs_has_index ? ASSIGN_FINAL : ASSIGN_CONST,
cctx);
if (lhs->lhs_scriptvar_idx >= 0)
{
scriptitem_T *si = SCRIPT_ITEM(
@@ -5665,7 +5691,7 @@ compile_lhs(
}
lhs->lhs_member_type = lhs->lhs_type;
if (lhs->lhs_dest_end > var_start + lhs->lhs_varlen)
if (lhs->lhs_has_index)
{
// Something follows after the variable: "var[idx]" or "var.key".
// TODO: should we also handle "->func()" here?
@@ -5700,7 +5726,6 @@ compile_lhs(
lhs->lhs_type = &t_any;
}
lhs->lhs_has_index = TRUE;
if (lhs->lhs_type->tt_member == NULL)
lhs->lhs_member_type = &t_any;
else