Patch 8.2.2331

4 views
Skip to first unread message

Bram Moolenaar

unread,
Jan 11, 2021, 3:20:58 PM1/11/21
to vim...@googlegroups.com

Patch 8.2.2331
Problem: Vim9: wrong error when modifying dict declared with :final.
Solution: Do not check for writable variable when an index follows.
(closes #7657)
Files: src/vim9compile.c, src/structs.h, src/vim9script.c,
src/proto/vim9script.pro, src/evalvars.c,
src/testdir/test_vim9_assign.vim


*** ../vim-8.2.2330/src/vim9compile.c 2021-01-11 20:17:30.395385392 +0100
--- src/vim9compile.c 2021-01-11 21:10:47.102931321 +0100
***************
*** 2127,2136 ****
}

/*
* Find "name" in script-local items of script "sid".
* Returns the index in "sn_var_vals" if found.
* If found but not in "sn_var_vals" returns -1.
! * If not found returns -2.
*/
int
get_script_item_idx(int sid, char_u *name, int check_writable, cctx_T *cctx)
--- 2127,2155 ----
}

/*
+ * 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 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,2158 ****
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);
return idx;
}

--- 2170,2177 ----
return -2;
idx = sav->sav_var_vals_idx;
sv = ((svar_T *)si->sn_var_vals.ga_data) + idx;
! if (check_item_writable(sv, check_writable, name) == FAIL)
! return -2;
return idx;
}

***************
*** 2168,2175 ****
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);
return idx;
}
}
--- 2187,2194 ----
sv = ((svar_T *)si->sn_var_vals.ga_data) + idx;
if (sv->sv_tv == &di->di_tv)
{
! if (check_item_writable(sv, check_writable, name) == FAIL)
! return -2;
return idx;
}
}
***************
*** 2466,2472 ****
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);
if (idx == -1 || si->sn_version != SCRIPT_VERSION_VIM9)
{
// variable is not in sn_var_vals: old style script.
--- 2485,2491 ----
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, 0, cctx);
if (idx == -1 || si->sn_version != SCRIPT_VERSION_VIM9)
{
// variable is not in sn_var_vals: old style script.
***************
*** 5475,5480 ****
--- 5494,5504 ----
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,5584 ****
lhs->lhs_scriptvar_sid = import->imp_sid;
if (SCRIPT_ID_VALID(lhs->lhs_scriptvar_sid))
{
lhs->lhs_scriptvar_idx = get_script_item_idx(
! lhs->lhs_scriptvar_sid,
! rawname, TRUE, cctx);
if (lhs->lhs_scriptvar_idx >= 0)
{
scriptitem_T *si = SCRIPT_ITEM(
--- 5600,5610 ----
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,
! lhs->lhs_has_index ? ASSIGN_FINAL : ASSIGN_CONST,
! cctx);
if (lhs->lhs_scriptvar_idx >= 0)
{
scriptitem_T *si = SCRIPT_ITEM(
***************
*** 5665,5671 ****
}

lhs->lhs_member_type = lhs->lhs_type;
! if (lhs->lhs_dest_end > var_start + lhs->lhs_varlen)
{
// Something follows after the variable: "var[idx]" or "var.key".
// TODO: should we also handle "->func()" here?
--- 5691,5697 ----
}

lhs->lhs_member_type = lhs->lhs_type;
! if (lhs->lhs_has_index)
{
// Something follows after the variable: "var[idx]" or "var.key".
// TODO: should we also handle "->func()" here?
***************
*** 5700,5706 ****
lhs->lhs_type = &t_any;
}

- lhs->lhs_has_index = TRUE;
if (lhs->lhs_type->tt_member == NULL)
lhs->lhs_member_type = &t_any;
else
--- 5726,5731 ----
*** ../vim-8.2.2330/src/structs.h 2021-01-10 18:33:08.011683523 +0100
--- src/structs.h 2021-01-11 20:49:32.530156868 +0100
***************
*** 1777,1783 ****
char_u *sv_name; // points into "sn_all_vars" di_key
typval_T *sv_tv; // points into "sn_vars" or "sn_all_vars" di_tv
type_T *sv_type;
! int sv_const;
int sv_export; // "export let var = val"
};

--- 1777,1783 ----
char_u *sv_name; // points into "sn_all_vars" di_key
typval_T *sv_tv; // points into "sn_vars" or "sn_all_vars" di_tv
type_T *sv_type;
! int sv_const; // 0, ASSIGN_CONST or ASSIGN_FINAL
int sv_export; // "export let var = val"
};

*** ../vim-8.2.2330/src/vim9script.c 2021-01-02 15:41:00.189079039 +0100
--- src/vim9script.c 2021-01-11 21:17:43.537953743 +0100
***************
*** 257,263 ****

// find name in "script"
// TODO: also find script-local user function
! idx = get_script_item_idx(sid, name, FALSE, cctx);
if (idx >= 0)
{
sv = ((svar_T *)script->sn_var_vals.ga_data) + idx;
--- 257,263 ----

// find name in "script"
// TODO: also find script-local user function
! idx = get_script_item_idx(sid, name, 0, cctx);
if (idx >= 0)
{
sv = ((svar_T *)script->sn_var_vals.ga_data) + idx;
***************
*** 661,670 ****
* with a hashtable) and sn_var_vals (lookup by index).
* When "create" is TRUE this is a new variable, otherwise find and update an
* existing variable.
* When "*type" is NULL use "tv" for the type and update "*type".
*/
void
! update_vim9_script_var(int create, dictitem_T *di, typval_T *tv, type_T **type)
{
scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid);
hashitem_T *hi;
--- 661,676 ----
* with a hashtable) and sn_var_vals (lookup by index).
* When "create" is TRUE this is a new variable, otherwise find and update an
* existing variable.
+ * "flags" can have ASSIGN_FINAL or ASSIGN_CONST.
* When "*type" is NULL use "tv" for the type and update "*type".
*/
void
! update_vim9_script_var(
! int create,
! dictitem_T *di,
! int flags,
! typval_T *tv,
! type_T **type)
{
scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid);
hashitem_T *hi;
***************
*** 686,692 ****
return;

sv->sv_tv = &di->di_tv;
! sv->sv_const = (di->di_flags & DI_FLAGS_LOCK) ? ASSIGN_CONST : 0;
sv->sv_export = is_export;
newsav->sav_var_vals_idx = si->sn_var_vals.ga_len;
++si->sn_var_vals.ga_len;
--- 692,699 ----
return;

sv->sv_tv = &di->di_tv;
! sv->sv_const = (flags & ASSIGN_FINAL) ? ASSIGN_FINAL
! : (flags & ASSIGN_CONST) ? ASSIGN_CONST : 0;
sv->sv_export = is_export;
newsav->sav_var_vals_idx = si->sn_var_vals.ga_len;
++si->sn_var_vals.ga_len;
***************
*** 864,870 ****

if (sv != NULL)
{
! if (sv->sv_const)
{
semsg(_(e_readonlyvar), name);
return FAIL;
--- 871,877 ----

if (sv != NULL)
{
! if (sv->sv_const != 0)
{
semsg(_(e_readonlyvar), name);
return FAIL;
*** ../vim-8.2.2330/src/proto/vim9script.pro 2021-01-02 15:41:00.189079039 +0100
--- src/proto/vim9script.pro 2021-01-11 21:18:15.993886632 +0100
***************
*** 10,16 ****
int find_exported(int sid, char_u *name, ufunc_T **ufunc, type_T **type, cctx_T *cctx);
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);
! void update_vim9_script_var(int create, dictitem_T *di, typval_T *tv, type_T **type);
void hide_script_var(scriptitem_T *si, int idx, int func_defined);
void free_all_script_vars(scriptitem_T *si);
svar_T *find_typval_in_script(typval_T *dest);
--- 10,16 ----
int find_exported(int sid, char_u *name, ufunc_T **ufunc, type_T **type, cctx_T *cctx);
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);
! void update_vim9_script_var(int create, dictitem_T *di, int flags, typval_T *tv, type_T **type);
void hide_script_var(scriptitem_T *si, int idx, int func_defined);
void free_all_script_vars(scriptitem_T *si);
svar_T *find_typval_in_script(typval_T *dest);
*** ../vim-8.2.2330/src/evalvars.c 2021-01-06 21:59:35.174021934 +0100
--- src/evalvars.c 2021-01-11 21:18:04.569910377 +0100
***************
*** 3153,3159 ****
// A Vim9 script-local variable is also present in sn_all_vars and
// sn_var_vals. It may set "type" from "tv".
if (is_script_local && vim9script)
! update_vim9_script_var(FALSE, di, tv, &type);
}

// existing variable, need to clear the value
--- 3153,3159 ----
// A Vim9 script-local variable is also present in sn_all_vars and
// sn_var_vals. It may set "type" from "tv".
if (is_script_local && vim9script)
! update_vim9_script_var(FALSE, di, flags, tv, &type);
}

// existing variable, need to clear the value
***************
*** 3243,3249 ****
// A Vim9 script-local variable is also added to sn_all_vars and
// sn_var_vals. It may set "type" from "tv".
if (is_script_local && vim9script)
! update_vim9_script_var(TRUE, di, tv, &type);
}

if (copy || tv->v_type == VAR_NUMBER || tv->v_type == VAR_FLOAT)
--- 3243,3249 ----
// A Vim9 script-local variable is also added to sn_all_vars and
// sn_var_vals. It may set "type" from "tv".
if (is_script_local && vim9script)
! update_vim9_script_var(TRUE, di, flags, tv, &type);
}

if (copy || tv->v_type == VAR_NUMBER || tv->v_type == VAR_FLOAT)
*** ../vim-8.2.2330/src/testdir/test_vim9_assign.vim 2021-01-09 12:09:18.399881402 +0100
--- src/testdir/test_vim9_assign.vim 2021-01-11 21:12:36.634631486 +0100
***************
*** 1225,1230 ****
--- 1225,1236 ----
g:dict_val = s:dict[key]
enddef
GetDictVal('a')
+
+ final adict: dict<string> = {}
+ def ChangeAdict()
+ adict.foo = 'foo'
+ enddef
+ ChangeAdict()
END
CheckScriptSuccess(lines)
assert_equal('', g:var_uninit)
***************
*** 1262,1267 ****
--- 1268,1283 ----

lines =<< trim END
vim9script
+ const cdict: dict<string> = {}
+ def Change()
+ cdict.foo = 'foo'
+ enddef
+ defcompile
+ END
+ CheckScriptFailure(lines, 'E46:')
+
+ lines =<< trim END
+ vim9script
final w:finalvar = [9]
w:finalvar = [8]
END
*** ../vim-8.2.2330/src/version.c 2021-01-11 20:17:30.395385392 +0100
--- src/version.c 2021-01-11 20:41:38.434932966 +0100
***************
*** 752,753 ****
--- 752,755 ----
{ /* Add new patch number below this line */
+ /**/
+ 2331,
/**/

--
hundred-and-one symptoms of being an internet addict:
128. You can access the Net -- via your portable and cellular phone.

/// Bram Moolenaar -- Br...@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 ///
Reply all
Reply to author
Forward
0 new messages