summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2022-10-11 20:04:09 +0100
committerBram Moolenaar <Bram@vim.org>2022-10-11 20:04:09 +0100
commita275f2cdcc4353e7653a69c7c818422db5da599d (patch)
tree5c14a63a542f0880495c5e77cf243daadb3b03a7
parenta9a364872e41932990aba1787af65f67c7e14917 (diff)
downloadvim-git-a275f2cdcc4353e7653a69c7c818422db5da599d.tar.gz
patch 9.0.0724: closure in compiled function gets same variable in blockv9.0.0724
Problem: Closure in compiled function gets same variable in block. Solution: At the end of a block to not always reset the variable count. (issue #11094)
-rw-r--r--src/testdir/test_vim9_script.vim30
-rw-r--r--src/version.c2
-rw-r--r--src/vim9cmds.c32
-rw-r--r--src/vim9compile.c3
4 files changed, 49 insertions, 18 deletions
diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim
index c736905d9..05fd2fb57 100644
--- a/src/testdir/test_vim9_script.vim
+++ b/src/testdir/test_vim9_script.vim
@@ -2314,6 +2314,36 @@ def Test_for_loop_with_closure()
END
v9.CheckDefAndScriptSuccess(lines)
+ # also with an extra block level
+ lines =<< trim END
+ var flist: list<func>
+ for i in range(5)
+ {
+ var inloop = i
+ flist[i] = () => inloop
+ }
+ endfor
+ for i in range(5)
+ assert_equal(i, flist[i]())
+ endfor
+ END
+ v9.CheckDefAndScriptSuccess(lines)
+
+ # and declaration in higher block
+ lines =<< trim END
+ var flist: list<func>
+ for i in range(5)
+ var inloop = i
+ {
+ flist[i] = () => inloop
+ }
+ endfor
+ for i in range(5)
+ assert_equal(i, flist[i]())
+ endfor
+ END
+ v9.CheckDefAndScriptSuccess(lines)
+
lines =<< trim END
var flist: list<func>
for i in range(5)
diff --git a/src/version.c b/src/version.c
index 9130e787a..1af1bcb3b 100644
--- a/src/version.c
+++ b/src/version.c
@@ -700,6 +700,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 724,
+/**/
723,
/**/
722,
diff --git a/src/vim9cmds.c b/src/vim9cmds.c
index d209a1664..a1e8ac18c 100644
--- a/src/vim9cmds.c
+++ b/src/vim9cmds.c
@@ -57,22 +57,20 @@ current_instr_idx(cctx_T *cctx)
}
/*
* Remove local variables above "new_top".
+ * Do this by clearing the name. If "keep" is TRUE do not reset the length, a
+ * closure may still need location of the variable.
*/
static void
-unwind_locals(cctx_T *cctx, int new_top)
+unwind_locals(cctx_T *cctx, int new_top, int keep)
{
if (cctx->ctx_locals.ga_len > new_top)
- {
- int idx;
- lvar_T *lvar;
-
- for (idx = new_top; idx < cctx->ctx_locals.ga_len; ++idx)
+ for (int idx = new_top; idx < cctx->ctx_locals.ga_len; ++idx)
{
- lvar = ((lvar_T *)cctx->ctx_locals.ga_data) + idx;
- vim_free(lvar->lv_name);
+ lvar_T *lvar = ((lvar_T *)cctx->ctx_locals.ga_data) + idx;
+ VIM_CLEAR(lvar->lv_name);
}
- }
- cctx->ctx_locals.ga_len = new_top;
+ if (!keep)
+ cctx->ctx_locals.ga_len = new_top;
}
/*
@@ -81,7 +79,7 @@ unwind_locals(cctx_T *cctx, int new_top)
void
free_locals(cctx_T *cctx)
{
- unwind_locals(cctx, 0);
+ unwind_locals(cctx, 0, FALSE);
ga_clear(&cctx->ctx_locals);
}
@@ -525,7 +523,7 @@ compile_elseif(char_u *arg, cctx_T *cctx)
emsg(_(e_elseif_without_if));
return NULL;
}
- unwind_locals(cctx, scope->se_local_count);
+ unwind_locals(cctx, scope->se_local_count, TRUE);
if (!cctx->ctx_had_return)
scope->se_u.se_if.is_had_return = FALSE;
@@ -672,7 +670,7 @@ compile_else(char_u *arg, cctx_T *cctx)
emsg(_(e_else_without_if));
return NULL;
}
- unwind_locals(cctx, scope->se_local_count);
+ unwind_locals(cctx, scope->se_local_count, TRUE);
if (!cctx->ctx_had_return)
scope->se_u.se_if.is_had_return = FALSE;
scope->se_u.se_if.is_seen_else = TRUE;
@@ -744,7 +742,7 @@ compile_endif(char_u *arg, cctx_T *cctx)
return NULL;
}
ifscope = &scope->se_u.se_if;
- unwind_locals(cctx, scope->se_local_count);
+ unwind_locals(cctx, scope->se_local_count, TRUE);
if (!cctx->ctx_had_return)
ifscope->is_had_return = FALSE;
@@ -1122,7 +1120,7 @@ compile_endfor(char_u *arg, cctx_T *cctx)
if (compile_loop_end(&forscope->fs_loop_info, cctx) == FAIL)
return NULL;
- unwind_locals(cctx, scope->se_local_count);
+ unwind_locals(cctx, scope->se_local_count, FALSE);
// At end of ":for" scope jump back to the FOR instruction.
generate_JUMP(cctx, JUMP_ALWAYS, forscope->fs_top_label);
@@ -1249,7 +1247,7 @@ compile_endwhile(char_u *arg, cctx_T *cctx)
if (compile_loop_end(&whilescope->ws_loop_info, cctx) == FAIL)
return NULL;
- unwind_locals(cctx, scope->se_local_count);
+ unwind_locals(cctx, scope->se_local_count, FALSE);
#ifdef FEAT_PROFILE
// count the endwhile before jumping
@@ -1471,7 +1469,7 @@ compile_endblock(cctx_T *cctx)
scope_T *scope = cctx->ctx_scope;
cctx->ctx_scope = scope->se_outer;
- unwind_locals(cctx, scope->se_local_count);
+ unwind_locals(cctx, scope->se_local_count, TRUE);
vim_free(scope);
}
diff --git a/src/vim9compile.c b/src/vim9compile.c
index 468c3846d..b3e1b83ea 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -47,7 +47,8 @@ lookup_local(char_u *name, size_t len, lvar_T *lvar, cctx_T *cctx)
for (idx = 0; idx < cctx->ctx_locals.ga_len; ++idx)
{
lvp = ((lvar_T *)cctx->ctx_locals.ga_data) + idx;
- if (STRNCMP(name, lvp->lv_name, len) == 0
+ if (lvp->lv_name != NULL
+ && STRNCMP(name, lvp->lv_name, len) == 0
&& STRLEN(lvp->lv_name) == len)
{
if (lvar != NULL)