0
0
mirror of https://github.com/vim/vim.git synced 2025-07-26 11:04:33 -04:00

patch 8.2.2193: Vim9: can change constant in :def function

Problem:    Vim9: can change constant in :def function.
Solution:   Check if a variable is locked. (issue #7526)
This commit is contained in:
Bram Moolenaar 2020-12-22 20:35:40 +01:00
parent e5492609b3
commit 3bdc90b7df
5 changed files with 39 additions and 10 deletions

View File

@ -3125,13 +3125,7 @@ set_var_const(
goto failed; goto failed;
} }
// Check in this order for backwards compatibility: if (var_check_permission(di, name) == FAIL)
// - Whether the variable is read-only
// - Whether the variable value is locked
// - Whether the variable is locked
if (var_check_ro(di->di_flags, name, FALSE)
|| value_check_lock(di->di_tv.v_lock, name, FALSE)
|| var_check_lock(di->di_flags, name, FALSE))
goto failed; goto failed;
} }
else else
@ -3242,6 +3236,22 @@ failed:
clear_tv(tv_arg); clear_tv(tv_arg);
} }
/*
* Check in this order for backwards compatibility:
* - Whether the variable is read-only
* - Whether the variable value is locked
* - Whether the variable is locked
*/
int
var_check_permission(dictitem_T *di, char_u *name)
{
if (var_check_ro(di->di_flags, name, FALSE)
|| value_check_lock(di->di_tv.v_lock, name, FALSE)
|| var_check_lock(di->di_flags, name, FALSE))
return FAIL;
return OK;
}
/* /*
* Return TRUE if di_flags "flags" indicates variable "name" is read-only. * Return TRUE if di_flags "flags" indicates variable "name" is read-only.
* Also give an error message. * Also give an error message.

View File

@ -70,6 +70,7 @@ void vars_clear_ext(hashtab_T *ht, int free_val);
void delete_var(hashtab_T *ht, hashitem_T *hi); void delete_var(hashtab_T *ht, hashitem_T *hi);
void set_var(char_u *name, typval_T *tv, int copy); void set_var(char_u *name, typval_T *tv, int copy);
void set_var_const(char_u *name, type_T *type, typval_T *tv_arg, int copy, int flags); void set_var_const(char_u *name, type_T *type, typval_T *tv_arg, int copy, int flags);
int var_check_permission(dictitem_T *di, char_u *name);
int var_check_ro(int flags, char_u *name, int use_gettext); int var_check_ro(int flags, char_u *name, int use_gettext);
int var_check_lock(int flags, char_u *name, int use_gettext); int var_check_lock(int flags, char_u *name, int use_gettext);
int var_check_fixed(int flags, char_u *name, int use_gettext); int var_check_fixed(int flags, char_u *name, int use_gettext);

View File

@ -1022,6 +1022,17 @@ def Test_vim9script_call_fail_const()
writefile(lines, 'Xcall_const.vim') writefile(lines, 'Xcall_const.vim')
assert_fails('source Xcall_const.vim', 'E46:', '', 1, 'MyFunc') assert_fails('source Xcall_const.vim', 'E46:', '', 1, 'MyFunc')
delete('Xcall_const.vim') delete('Xcall_const.vim')
lines =<< trim END
const g:Aconst = 77
def Change()
# comment
g:Aconst = 99
enddef
call Change()
unlet g:Aconst
END
CheckScriptFailure(lines, 'E741: Value is locked: Aconst', 2)
enddef enddef
" Test that inside :function a Python function can be defined, :def is not " Test that inside :function a Python function can be defined, :def is not

View File

@ -750,6 +750,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
2193,
/**/ /**/
2192, 2192,
/**/ /**/

View File

@ -1693,8 +1693,10 @@ call_def_function(
case ISN_STOREW: case ISN_STOREW:
case ISN_STORET: case ISN_STORET:
{ {
dictitem_T *di; dictitem_T *di;
hashtab_T *ht; hashtab_T *ht;
char_u *name = iptr->isn_arg.string + 2;
switch (iptr->isn_type) switch (iptr->isn_type)
{ {
case ISN_STOREG: case ISN_STOREG:
@ -1714,11 +1716,14 @@ call_def_function(
} }
--ectx.ec_stack.ga_len; --ectx.ec_stack.ga_len;
di = find_var_in_ht(ht, 0, iptr->isn_arg.string + 2, TRUE); di = find_var_in_ht(ht, 0, name, TRUE);
if (di == NULL) if (di == NULL)
store_var(iptr->isn_arg.string, STACK_TV_BOT(0)); store_var(iptr->isn_arg.string, STACK_TV_BOT(0));
else else
{ {
SOURCING_LNUM = iptr->isn_lnum;
if (var_check_permission(di, name) == FAIL)
goto on_error;
clear_tv(&di->di_tv); clear_tv(&di->di_tv);
di->di_tv = *STACK_TV_BOT(0); di->di_tv = *STACK_TV_BOT(0);
} }