patch 9.2.1136: Vim9: cannot change an item of a read-only v: variable in :def

Problem:  Assigning to an item of a read-only v: variable, gives E46 in
          a :def function, while it works at the script level and
          ":help clipboard-providers-define" does it.
Solution: Check that a v: variable is read-only only when no index
          follows, as for a script variable.  Make v:clipproviders an
          empty dict at startup, as v:colornames, so that a :def function
          can add the first item.

closes: #21391

Assisted-by: Claude
Signed-off-by: Hirohito Higashi <h.east.727@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
Hirohito Higashi authored and Christian Brabandt committed 2026-09-28 17:52:19 +00:00
1 parent 10b37abb11
commit 0104c2052a
6 files changed
+32 -3

No files matched your search

+1
View File
@@ -273,6 +273,7 @@ evalvars_init(void)
set_vim_var_nr(VV_ECHOSPACE, sc_col - 1);
set_vim_var_dict(VV_COLORNAMES, dict_alloc());
set_vim_var_dict(VV_CLIPPROVIDERS, dict_alloc());
#ifdef FEAT_PYTHON3
set_vim_var_nr(VV_PYTHON3_VERSION, python3_version());
+1 -1
View File
@@ -22,7 +22,7 @@ char_u *compile_one_expr_in_str(char_u *p, cctx_T *cctx);
int compile_all_expr_in_str(char_u *str, int evalstr, cctx_T *cctx);
int assignment_len(char_u *p, int *heredoc);
void vim9_declare_error(char_u *name);
int get_var_dest(char_u *name, assign_dest_T *dest, cmdidx_T cmdidx, int *option_scope, int *vimvaridx, type_T **type, cctx_T *cctx);
int get_var_dest(char_u *name, assign_dest_T *dest, cmdidx_T cmdidx, int has_index, int *option_scope, int *vimvaridx, type_T **type, cctx_T *cctx);
int compile_lhs(char_u *var_start, lhs_T *lhs, cmdidx_T cmdidx, int heredoc, int has_cmd, int oplen, cctx_T *cctx);
int compile_assign_lhs(char_u *var_start, lhs_T *lhs, cmdidx_T cmdidx, int is_decl, int heredoc, int has_cmd, int oplen, cctx_T *cctx);
int compile_load_lhs_with_index(lhs_T *lhs, char_u *var_start, cctx_T *cctx);
+22
View File
@@ -248,6 +248,28 @@ def Test_assignment()
END
enddef
" An item of a read-only v: variable can be changed in a :def function, as
" at the script level, the variable itself cannot.
def Test_assign_item_of_readonly_vim_var()
assert_equal(v:t_dict, type(v:clipproviders))
var lines =<< trim END
vim9script
def Define()
v:clipproviders['vim9_one'] = {}
v:clipproviders.vim9_two = {}
enddef
Define()
assert_equal({}, v:clipproviders.vim9_one)
assert_equal({}, v:clipproviders.vim9_two)
remove(v:clipproviders, 'vim9_one')
remove(v:clipproviders, 'vim9_two')
END
v9.CheckScriptSuccess(lines)
v9.CheckDefFailure(['v:clipproviders = {}'], 'E46:')
v9.CheckDefFailure(['v:version[0] = 1'], 'E1141:')
enddef
def Test_float_and_number()
var lines =<< trim END
var f: float
+2
View File
@@ -763,6 +763,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
1136,
/**/
1135,
/**/
+1 -1
View File
@@ -1151,7 +1151,7 @@ compile_for(char_u *arg_start, cctx_T *cctx)
goto failed;
}
if (get_var_dest(name, &dest, CMD_for, &opt_flags,
if (get_var_dest(name, &dest, CMD_for, FALSE, &opt_flags,
&vimvaridx, &type, cctx) == FAIL)
goto failed;
if (dest != dest_local)
+5 -1
View File
@@ -1493,6 +1493,7 @@ valid_dest_reg(int name)
* For an option "option_scope" is set.
* For a v:var "vimvaridx" is set.
* "type" is set to the destination type if known, unchanted otherwise.
* When "has_index" is TRUE an item of the variable is assigned to.
* Return FAIL if an error message was given.
*/
int
@@ -1500,6 +1501,7 @@ get_var_dest(
char_u *name,
assign_dest_T *dest,
cmdidx_T cmdidx,
int has_index,
int *option_scope,
int *vimvaridx,
type_T **type,
@@ -1600,8 +1602,9 @@ get_var_dest(
semsg(_(e_variable_not_found_str), name);
return FAIL;
}
// An item of a read-only variable can be changed, as when not compiled.
// We use the current value of "sandbox" here, is that OK?
if (var_check_ro(di_flags, name, FALSE))
if (!has_index && var_check_ro(di_flags, name, FALSE))
return FAIL;
*dest = dest_vimvar;
vtv = get_vim_var_tv(*vimvaridx);
@@ -1961,6 +1964,7 @@ compile_lhs_var_dest(
int declare_error = FALSE;
if (get_var_dest(lhs->lhs_name, &lhs->lhs_dest, cmdidx,
lhs->lhs_has_index,
&lhs->lhs_opt_flags, &lhs->lhs_vimvaridx,
&lhs->lhs_type, cctx) == FAIL)
return FAIL;