diff options
author | Bram Moolenaar <Bram@vim.org> | 2022-10-11 20:04:09 +0100 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2022-10-11 20:04:09 +0100 |
commit | a275f2cdcc4353e7653a69c7c818422db5da599d (patch) | |
tree | 5c14a63a542f0880495c5e77cf243daadb3b03a7 | |
parent | a9a364872e41932990aba1787af65f67c7e14917 (diff) | |
download | vim-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.vim | 30 | ||||
-rw-r--r-- | src/version.c | 2 | ||||
-rw-r--r-- | src/vim9cmds.c | 32 | ||||
-rw-r--r-- | src/vim9compile.c | 3 |
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) |