# HG changeset patch # User Bram Moolenaar # Date 1608666304 -3600 # Node ID d9ae7dd3a0f22067deb7b0a4585ae8113b691204 # Parent 38b22245d35ceed60ed85dd0f955ed92d603c996 patch 8.2.2193: Vim9: can change constant in :def function Commit: https://github.com/vim/vim/commit/3bdc90b7dfab314768a8f56454ea62929524f05c Author: Bram Moolenaar Date: Tue Dec 22 20:35:40 2020 +0100 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 https://github.com/vim/vim/issues/7526) diff --git a/src/evalvars.c b/src/evalvars.c --- a/src/evalvars.c +++ b/src/evalvars.c @@ -3125,13 +3125,7 @@ set_var_const( goto failed; } - // Check in this order for backwards compatibility: - // - 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)) + if (var_check_permission(di, name) == FAIL) goto failed; } else @@ -3243,6 +3237,22 @@ failed: } /* + * 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. * Also give an error message. */ diff --git a/src/proto/evalvars.pro b/src/proto/evalvars.pro --- a/src/proto/evalvars.pro +++ b/src/proto/evalvars.pro @@ -70,6 +70,7 @@ void vars_clear_ext(hashtab_T *ht, int f void delete_var(hashtab_T *ht, hashitem_T *hi); 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); +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_lock(int flags, char_u *name, int use_gettext); int var_check_fixed(int flags, char_u *name, int use_gettext); diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -1022,6 +1022,17 @@ def Test_vim9script_call_fail_const() writefile(lines, 'Xcall_const.vim') assert_fails('source Xcall_const.vim', 'E46:', '', 1, 'MyFunc') 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 " Test that inside :function a Python function can be defined, :def is not diff --git a/src/version.c b/src/version.c --- 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 */ /**/ + 2193, +/**/ 2192, /**/ 2191, diff --git a/src/vim9execute.c b/src/vim9execute.c --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -1693,8 +1693,10 @@ call_def_function( case ISN_STOREW: case ISN_STORET: { - dictitem_T *di; - hashtab_T *ht; + dictitem_T *di; + hashtab_T *ht; + char_u *name = iptr->isn_arg.string + 2; + switch (iptr->isn_type) { case ISN_STOREG: @@ -1714,11 +1716,14 @@ call_def_function( } --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) store_var(iptr->isn_arg.string, STACK_TV_BOT(0)); else { + SOURCING_LNUM = iptr->isn_lnum; + if (var_check_permission(di, name) == FAIL) + goto on_error; clear_tv(&di->di_tv); di->di_tv = *STACK_TV_BOT(0); }