]> granicus.if.org Git - vim/commitdiff
patch 8.2.4682: Vim9: can use :unlockvar for const variable v8.2.4682
authorBram Moolenaar <Bram@vim.org>
Mon, 4 Apr 2022 13:58:06 +0000 (14:58 +0100)
committerBram Moolenaar <Bram@vim.org>
Mon, 4 Apr 2022 13:58:06 +0000 (14:58 +0100)
Problem:    Vim9: can use :unlockvar for const variable. (Ernie Rael)
Solution:   Check whether the variable is a const.

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

index 2cde6421618362f859a20417d5ff40a715779f23..b30577fecc168879563f91d0c0128169ba5b1b30 100644 (file)
@@ -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)
index dd70427d32f31407de265f49d95a1dfa03983cc7..c1ec5b0bab578a64b30b5eb11dad0ad42288fa41 100644 (file)
@@ -1951,23 +1951,42 @@ do_lock_var(
                                                                  lp->ll_name);
                ret = FAIL;
            }
-           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;
+               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
-                   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)
                {
index c12f151c3a6632d965600302642fac1d9690b977..2d5752445b0e6675d966b1d3daf8a8ac51452c80 100644 (file)
@@ -303,7 +303,6 @@ static void ex_tag_cmd(exarg_T *eap, char_u *name);
 # 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
index bc1e23275ceed3385b960e8824a9016e429f5aee..04c07fc325af329eb176e6fb56dbb2c94f4606fc 100644 (file)
@@ -16,7 +16,7 @@ int find_exported(int sid, char_u *name, ufunc_T **ufunc, type_T **type, cctx_T
 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 : */
index 8dea71d5f542adbb01d570005f1b1926bdb640c9..49ca29b676aee8cce1efaaae65ffb60716e2a925 100644 (file)
@@ -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()
index 052923e94c910db866497350106381ade8c4d00f..c80a49051ce2932796ee546f0dbf64a4b6791451 100644 (file)
@@ -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;
index 79a3bad67db75489d1da0f94de3bd813bdea2904..8b7450c66767b1b198262301209991561c1e1949 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    4682,
 /**/
     4681,
 /**/
index cd9ff92cd66350e7b943cac8d57fe31f010a8ba0..adb01e8b97a0faf085204df00d4d45427b34b1ab 100644 (file)
@@ -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 idx, int func_defined)
 /*
  * 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, scid_T sid)
        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;
 }