summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2022-01-26 21:01:15 +0000
committerBram Moolenaar <Bram@vim.org>2022-01-26 21:01:15 +0000
commit70c43d84be98ab54d3723155dcc4232dc5a5f081 (patch)
tree31f3a580fe1bbfecc50e822e718696836d9cb95c
parent1080c48ec8d672d7e9fbefb5a1255c9df09a2884 (diff)
downloadvim-git-70c43d84be98ab54d3723155dcc4232dc5a5f081.tar.gz
patch 8.2.4225: Vim9: depth argument of :lockvar not parsed in :def functionv8.2.4225
Problem: Vim9: depth argument of :lockvar not parsed in :def function. Solution: Parse the optional depth argument. (closes #9629) Fix that locking doesn't work for a non-materialize list.
-rw-r--r--src/errors.h8
-rw-r--r--src/evalfunc.c7
-rw-r--r--src/evalvars.c16
-rw-r--r--src/structs.h8
-rw-r--r--src/testdir/test_vim9_cmd.vim29
-rw-r--r--src/testdir/test_vim9_disassemble.vim2
-rw-r--r--src/version.c2
-rw-r--r--src/vim9cmds.c23
-rw-r--r--src/vim9execute.c5
9 files changed, 82 insertions, 18 deletions
diff --git a/src/errors.h b/src/errors.h
index d89c27c22..dd1b9fcc8 100644
--- a/src/errors.h
+++ b/src/errors.h
@@ -2859,10 +2859,10 @@ EXTERN char e_assert_fails_fifth_argument[]
INIT(= N_("E1116: \"assert_fails()\" fifth argument must be a string"));
EXTERN char e_cannot_use_bang_with_nested_def[]
INIT(= N_("E1117: Cannot use ! with nested :def"));
-EXTERN char e_cannot_change_list[]
- INIT(= N_("E1118: Cannot change list"));
-EXTERN char e_cannot_change_list_item[]
- INIT(= N_("E1119: Cannot change list item"));
+EXTERN char e_cannot_change_locked_list[]
+ INIT(= N_("E1118: Cannot change locked list"));
+EXTERN char e_cannot_change_locked_list_item[]
+ INIT(= N_("E1119: Cannot change locked list item"));
EXTERN char e_cannot_change_dict[]
INIT(= N_("E1120: Cannot change dict"));
EXTERN char e_cannot_change_dict_item[]
diff --git a/src/evalfunc.c b/src/evalfunc.c
index 4376318d0..169f972c2 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -7922,7 +7922,7 @@ range_list_materialize(list_T *list)
{
varnumber_T start = list->lv_u.nonmat.lv_start;
varnumber_T end = list->lv_u.nonmat.lv_end;
- int stride = list->lv_u.nonmat.lv_stride;
+ int stride = list->lv_u.nonmat.lv_stride;
varnumber_T i;
list->lv_first = NULL;
@@ -7930,8 +7930,13 @@ range_list_materialize(list_T *list)
list->lv_len = 0;
list->lv_u.mat.lv_idx_item = NULL;
for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
+ {
if (list_append_number(list, (varnumber_T)i) == FAIL)
break;
+ if (list->lv_lock & VAR_ITEMS_LOCKED)
+ list->lv_u.mat.lv_last->li_tv.v_lock = VAR_LOCKED;
+ }
+ list->lv_lock &= ~VAR_ITEMS_LOCKED;
}
/*
diff --git a/src/evalvars.c b/src/evalvars.c
index 496666e1e..c53cc87fb 100644
--- a/src/evalvars.c
+++ b/src/evalvars.c
@@ -2060,10 +2060,18 @@ item_lock(typval_T *tv, int deep, int lock, int check_refcount)
l->lv_lock |= VAR_LOCKED;
else
l->lv_lock &= ~VAR_LOCKED;
- if ((deep < 0 || deep > 1) && l->lv_first != &range_list_item)
- // recursive: lock/unlock the items the List contains
- FOR_ALL_LIST_ITEMS(l, li)
- item_lock(&li->li_tv, deep - 1, lock, check_refcount);
+ if (deep < 0 || deep > 1)
+ {
+ if (l->lv_first == &range_list_item)
+ l->lv_lock |= VAR_ITEMS_LOCKED;
+ else
+ {
+ // recursive: lock/unlock the items the List contains
+ CHECK_LIST_MATERIALIZE(l);
+ FOR_ALL_LIST_ITEMS(l, li) item_lock(&li->li_tv,
+ deep - 1, lock, check_refcount);
+ }
+ }
}
break;
case VAR_DICT:
diff --git a/src/structs.h b/src/structs.h
index e2f1de93a..a35361ecb 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -1464,8 +1464,9 @@ typedef struct
// allowed to mask existing functions
// Values for "v_lock".
-#define VAR_LOCKED 1 // locked with lock(), can use unlock()
-#define VAR_FIXED 2 // locked forever
+#define VAR_LOCKED 1 // locked with lock(), can use unlock()
+#define VAR_FIXED 2 // locked forever
+#define VAR_ITEMS_LOCKED 4 // items of non-materialized list locked
/*
* Structure to hold an item of a list: an internal variable without a name.
@@ -1497,7 +1498,8 @@ struct listwatch_S
*/
struct listvar_S
{
- listitem_T *lv_first; // first item, NULL if none
+ listitem_T *lv_first; // first item, NULL if none, &range_list_item
+ // for a non-materialized list
listwatch_T *lv_watch; // first watcher, NULL if none
union {
struct { // used for non-materialized range list:
diff --git a/src/testdir/test_vim9_cmd.vim b/src/testdir/test_vim9_cmd.vim
index 6347a282a..7b2edfd1b 100644
--- a/src/testdir/test_vim9_cmd.vim
+++ b/src/testdir/test_vim9_cmd.vim
@@ -1396,6 +1396,35 @@ def Test_lockvar()
lockvar whatever
endif
+ g:lockme = [1, 2, 3]
+ lockvar 1 g:lockme
+ g:lockme[1] = 77
+ assert_equal([1, 77, 3], g:lockme)
+
+ lockvar 2 g:lockme
+ var caught = false
+ try
+ g:lockme[1] = 99
+ catch /E1119:/
+ caught = true
+ endtry
+ assert_true(caught)
+ assert_equal([1, 77, 3], g:lockme)
+ unlet g:lockme
+
+ # also for non-materialized list
+ g:therange = range(3)
+ lockvar 2 g:therange
+ caught = false
+ try
+ g:therange[1] = 99
+ catch /E1119:/
+ caught = true
+ endtry
+ assert_true(caught)
+ assert_equal([0, 1, 2], g:therange)
+ unlet g:therange
+
var d = {a: 1, b: 2}
d.a = 3
d.b = 4
diff --git a/src/testdir/test_vim9_disassemble.vim b/src/testdir/test_vim9_disassemble.vim
index 8731052aa..d3330908e 100644
--- a/src/testdir/test_vim9_disassemble.vim
+++ b/src/testdir/test_vim9_disassemble.vim
@@ -625,7 +625,7 @@ def Test_disassemble_locl_local()
'\d STORE $0\_s*' ..
'lockvar d.a\_s*' ..
'\d LOAD $0\_s*' ..
- '\d LOCKUNLOCK lockvar d.a\_s*',
+ '\d LOCKUNLOCK lockvar 2 d.a\_s*',
res)
enddef
diff --git a/src/version.c b/src/version.c
index 9869aa0d8..7fbafc604 100644
--- 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 */
/**/
+ 4225,
+/**/
4224,
/**/
4223,
diff --git a/src/vim9cmds.c b/src/vim9cmds.c
index 27322df1c..1af2a157e 100644
--- a/src/vim9cmds.c
+++ b/src/vim9cmds.c
@@ -178,7 +178,7 @@ compile_lock_unlock(
lval_T *lvp,
char_u *name_end,
exarg_T *eap,
- int deep UNUSED,
+ int deep,
void *coookie)
{
cctx_T *cctx = coookie;
@@ -223,8 +223,9 @@ compile_lock_unlock(
ret = FAIL;
else
{
- vim_snprintf((char *)buf, len, "%s %s",
+ vim_snprintf((char *)buf, len, "%s %d %s",
eap->cmdidx == CMD_lockvar ? "lockvar" : "unlockvar",
+ deep,
p);
ret = generate_EXEC_copy(cctx, isn, buf);
@@ -241,7 +242,23 @@ compile_lock_unlock(
char_u *
compile_unletlock(char_u *arg, exarg_T *eap, cctx_T *cctx)
{
- ex_unletlock(eap, arg, 0, GLV_NO_AUTOLOAD | GLV_COMPILING,
+ int deep = 0;
+ char_u *p = arg;
+
+ if (eap->cmdidx != CMD_unlet)
+ {
+ if (eap->forceit)
+ deep = -1;
+ else if (vim_isdigit(*p))
+ {
+ deep = getdigits(&p);
+ p = skipwhite(p);
+ }
+ else
+ deep = 2;
+ }
+
+ ex_unletlock(eap, p, deep, GLV_NO_AUTOLOAD | GLV_COMPILING,
eap->cmdidx == CMD_unlet ? compile_unlet : compile_lock_unlock,
cctx);
return eap->nextcmd == NULL ? (char_u *)"" : eap->nextcmd;
diff --git a/src/vim9execute.c b/src/vim9execute.c
index 1232b35bb..a45d7c553 100644
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -1754,7 +1754,8 @@ execute_storeindex(isn_T *iptr, ectx_T *ectx)
{
listitem_T *li = list_find(list, lidx);
- if (error_if_locked(li->li_tv.v_lock, e_cannot_change_list_item))
+ if (error_if_locked(li->li_tv.v_lock,
+ e_cannot_change_locked_list_item))
return FAIL;
// overwrite existing list item
clear_tv(&li->li_tv);
@@ -1762,7 +1763,7 @@ execute_storeindex(isn_T *iptr, ectx_T *ectx)
}
else
{
- if (error_if_locked(list->lv_lock, e_cannot_change_list))
+ if (error_if_locked(list->lv_lock, e_cannot_change_locked_list))
return FAIL;
// append to list, only fails when out of memory
if (list_append_tv(list, tv) == FAIL)