]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 8.2.2193: Vim9: can change constant in :def function v8.2.2193
authorBram Moolenaar <Bram@vim.org>
Tue, 22 Dec 2020 19:35:40 +0000 (20:35 +0100)
committerBram Moolenaar <Bram@vim.org>
Tue, 22 Dec 2020 19:35:40 +0000 (20:35 +0100)
Problem:    Vim9: can change constant in :def function.
Solution:   Check if a variable is locked. (issue #7526)

src/evalvars.c
src/proto/evalvars.pro
src/testdir/test_vim9_func.vim
src/version.c
src/vim9execute.c

index 572e5d5567a82fbef2874819590a7f8c4f6b6aaa..ec3f508ed3fcc51843ed9d1da511913770cccf64 100644 (file)
@@ -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
@@ -3242,6 +3236,22 @@ failed:
        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.
  * Also give an error message.
index 4c9d64582302f1dbb39fc588c9360799a2a25f97..c597ca37200fc780c435177da7126068baa4c99d 100644 (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 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);
index eadd1d1c3f91389dd59db82759bdb5ef4d4f1696..bdced0257b60e44b15c00f26ea5f3402d2195d44 100644 (file)
@@ -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
index 7c9529b55b974cf075c822dab5f2dc5c70d402d4..73a80aaf96bdb0bd0f003d212d84310e36a458b0 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2193,
 /**/
     2192,
 /**/
index 9636cbffa6bcbc6de0cc61fc1edca2589ac64cb4..90b4e0ba6b4f14477509431201a38c9a906fcaf1 100644 (file)
@@ -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);
                    }