changeset 28313:b418e073b42f v8.2.4682

patch 8.2.4682: Vim9: can use :unlockvar for const variable Commit: https://github.com/vim/vim/commit/7a411a306f90339d8686e42ac16e1ae4fc7533c5 Author: Bram Moolenaar <Bram@vim.org> 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.
author Bram Moolenaar <Bram@vim.org>
date Mon, 04 Apr 2022 16:00:03 +0200
parents fb6d65010f23
children 7bc5b23adf8f
files src/eval.c src/evalvars.c src/ex_docmd.c src/proto/vim9script.pro src/testdir/test_vim9_cmd.vim src/userfunc.c src/version.c src/vim9script.c
diffstat 8 files changed, 62 insertions(+), 23 deletions(-) [+]
line wrap: on
line diff
--- 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)
--- 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)
 		{
--- 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
--- 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 : */
--- 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()
--- 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;
--- 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,
--- 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;
 }