# HG changeset patch # User Bram Moolenaar # Date 1649080803 -7200 # Node ID b418e073b42f32776231e0d76924f3448a7ac090 # Parent fb6d65010f234bfa87991fa63eb71f22a0c463ad patch 8.2.4682: Vim9: can use :unlockvar for const variable Commit: https://github.com/vim/vim/commit/7a411a306f90339d8686e42ac16e1ae4fc7533c5 Author: Bram Moolenaar Date: Mon Apr 4 14:58:06 2022 +0100 patch 8.2.4682: Vim9: can use :unlockvar for const variable Problem: Vim9: can use :unlockvar for const variable. (Ernie Rael) Solution: Check whether the variable is a const. diff --git a/src/eval.c b/src/eval.c --- a/src/eval.c +++ b/src/eval.c @@ -1065,7 +1065,7 @@ get_lval( && lp->ll_tv == &v->di_tv && ht != NULL && ht == get_script_local_ht()) { - svar_T *sv = find_typval_in_script(lp->ll_tv, 0); + svar_T *sv = find_typval_in_script(lp->ll_tv, 0, TRUE); // Vim9 script local variable: get the type if (sv != NULL) diff --git a/src/evalvars.c b/src/evalvars.c --- a/src/evalvars.c +++ b/src/evalvars.c @@ -1951,23 +1951,42 @@ do_lock_var( lp->ll_name); ret = FAIL; } - else if ((di->di_flags & DI_FLAGS_FIX) + else + { + if ((di->di_flags & DI_FLAGS_FIX) && di->di_tv.v_type != VAR_DICT && di->di_tv.v_type != VAR_LIST) - { - // For historic reasons this error is not given for a list or - // dict. E.g., the b: dict could be locked/unlocked. - semsg(_(e_cannot_lock_or_unlock_variable_str), lp->ll_name); - ret = FAIL; - } - else - { - if (lock) - di->di_flags |= DI_FLAGS_LOCK; + { + // For historic reasons this error is not given for a list + // or dict. E.g., the b: dict could be locked/unlocked. + semsg(_(e_cannot_lock_or_unlock_variable_str), lp->ll_name); + ret = FAIL; + } else - di->di_flags &= ~DI_FLAGS_LOCK; - if (deep != 0) - item_lock(&di->di_tv, deep, lock, FALSE); + { + if (in_vim9script()) + { + svar_T *sv = find_typval_in_script(&di->di_tv, + 0, FALSE); + + if (sv != NULL && sv->sv_const != 0) + { + semsg(_(e_cannot_change_readonly_variable_str), + lp->ll_name); + ret = FAIL; + } + } + + if (ret == OK) + { + if (lock) + di->di_flags |= DI_FLAGS_LOCK; + else + di->di_flags &= ~DI_FLAGS_LOCK; + if (deep != 0) + item_lock(&di->di_tv, deep, lock, FALSE); + } + } } } *name_end = cc; @@ -2812,7 +2831,7 @@ eval_variable( if (ht != NULL && ht == get_script_local_ht() && tv != &SCRIPT_SV(current_sctx.sc_sid)->sv_var.di_tv) { - svar_T *sv = find_typval_in_script(tv, 0); + svar_T *sv = find_typval_in_script(tv, 0, TRUE); if (sv != NULL) type = sv->sv_type; @@ -3557,7 +3576,7 @@ set_var_const( if (var_in_vim9script && (flags & ASSIGN_FOR_LOOP) == 0) { where_T where = WHERE_INIT; - svar_T *sv = find_typval_in_script(&di->di_tv, sid); + svar_T *sv = find_typval_in_script(&di->di_tv, sid, TRUE); if (sv != NULL) { diff --git a/src/ex_docmd.c b/src/ex_docmd.c --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -303,7 +303,6 @@ static void ex_tag_cmd(exarg_T *eap, cha # define ex_throw ex_ni # define ex_try ex_ni # define ex_unlet ex_ni -# define ex_unlockvar ex_ni # define ex_while ex_ni # define ex_import ex_ni # define ex_export ex_ni diff --git a/src/proto/vim9script.pro b/src/proto/vim9script.pro --- a/src/proto/vim9script.pro +++ b/src/proto/vim9script.pro @@ -16,7 +16,7 @@ int find_exported(int sid, char_u *name, char_u *vim9_declare_scriptvar(exarg_T *eap, char_u *arg); void update_vim9_script_var(int create, dictitem_T *di, char_u *name, int flags, typval_T *tv, type_T **type, int do_member); void hide_script_var(scriptitem_T *si, int idx, int func_defined); -svar_T *find_typval_in_script(typval_T *dest, scid_T sid); +svar_T *find_typval_in_script(typval_T *dest, scid_T sid, int must_find); int check_script_var_type(svar_T *sv, typval_T *value, char_u *name, where_T where); int check_reserved_name(char_u *name); /* vim: set ft=c : */ diff --git a/src/testdir/test_vim9_cmd.vim b/src/testdir/test_vim9_cmd.vim --- a/src/testdir/test_vim9_cmd.vim +++ b/src/testdir/test_vim9_cmd.vim @@ -1650,6 +1650,23 @@ def Test_lockvar() LockIt() END v9.CheckScriptFailure(lines, 'E1246', 1) + + lines =<< trim END + vim9script + const name = 'john' + unlockvar name + END + v9.CheckScriptFailure(lines, 'E46', 3) + + lines =<< trim END + vim9script + const name = 'john' + def UnLockIt() + unlockvar name + enddef + UnLockIt() + END + v9.CheckScriptFailure(lines, 'E46', 1) enddef def Test_substitute_expr() diff --git a/src/userfunc.c b/src/userfunc.c --- a/src/userfunc.c +++ b/src/userfunc.c @@ -1697,7 +1697,7 @@ deref_func_name( { if (!did_type && type != NULL && ht == get_script_local_ht()) { - svar_T *sv = find_typval_in_script(tv, 0); + svar_T *sv = find_typval_in_script(tv, 0, TRUE); if (sv != NULL) *type = sv->sv_type; 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 */ /**/ + 4682, +/**/ 4681, /**/ 4680, diff --git a/src/vim9script.c b/src/vim9script.c --- a/src/vim9script.c +++ b/src/vim9script.c @@ -956,7 +956,7 @@ update_vim9_script_var( } else { - sv = find_typval_in_script(&di->di_tv, 0); + sv = find_typval_in_script(&di->di_tv, 0, TRUE); } if (sv != NULL) { @@ -1053,10 +1053,11 @@ hide_script_var(scriptitem_T *si, int id /* * Find the script-local variable that links to "dest". * If "sid" is zero use the current script. + * if "must_find" is TRUE and "dest" cannot be found report an internal error. * Returns NULL if not found and give an internal error. */ svar_T * -find_typval_in_script(typval_T *dest, scid_T sid) +find_typval_in_script(typval_T *dest, scid_T sid, int must_find) { scriptitem_T *si = SCRIPT_ITEM(sid == 0 ? current_sctx.sc_sid : sid); int idx; @@ -1076,7 +1077,8 @@ find_typval_in_script(typval_T *dest, sc if (sv->sv_name != NULL && sv->sv_tv == dest) return sv; } - iemsg("find_typval_in_script(): not found"); + if (must_find) + iemsg("find_typval_in_script(): not found"); return NULL; }