summaryrefslogtreecommitdiff
path: root/src/vim9instr.c
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2022-09-19 15:54:34 +0100
committerBram Moolenaar <Bram@vim.org>2022-09-19 15:54:34 +0100
commitcc34181f9994d64f8c8fa2f5845eaf0cc963067f (patch)
tree2909cd6f0d4d5f7e20b7daa76855c25fdef5dcb9 /src/vim9instr.c
parent18ee0feb5dfbe51993dc715d24cf419ac92ebf92 (diff)
downloadvim-git-cc34181f9994d64f8c8fa2f5845eaf0cc963067f.tar.gz
patch 9.0.0502: a closure in a nested loop in a :def function does not workv9.0.0502
Problem: A closure in a nested loop in a :def function does not work. Solution: Use an array of loopvars, one per loop level.
Diffstat (limited to 'src/vim9instr.c')
-rw-r--r--src/vim9instr.c44
1 files changed, 23 insertions, 21 deletions
diff --git a/src/vim9instr.c b/src/vim9instr.c
index edc6cb61d..85a49a893 100644
--- a/src/vim9instr.c
+++ b/src/vim9instr.c
@@ -997,6 +997,7 @@ generate_LOADOUTER(
cctx_T *cctx,
int idx,
int nesting,
+ int loop_depth,
int loop_idx,
type_T *type)
{
@@ -1008,9 +1009,9 @@ generate_LOADOUTER(
if (nesting == 1 && loop_idx >= 0 && idx >= loop_idx)
{
// Load a variable defined in a loop. A copy will be made at the end
- // of the loop. TODO: how about deeper nesting?
+ // of the loop.
isn->isn_arg.outer.outer_idx = idx - loop_idx;
- isn->isn_arg.outer.outer_depth = OUTER_LOOP_DEPTH;
+ isn->isn_arg.outer.outer_depth = -loop_depth - 1;
}
else
{
@@ -1207,8 +1208,8 @@ generate_FUNCREF(
isn_T *isn;
type_T *type;
funcref_extra_T *extra;
- short loop_var_idx;
- short loop_var_count;
+ loopvarinfo_T loopinfo;
+ int has_vars;
RETURN_OK_IF_SKIP(cctx);
if ((isn = generate_instr(cctx, ISN_FUNCREF)) == NULL)
@@ -1216,20 +1217,22 @@ generate_FUNCREF(
if (isnp != NULL)
*isnp = isn;
- loop_var_count = get_loop_var_info(cctx, &loop_var_idx);
- if (ufunc->uf_def_status == UF_NOT_COMPILED || loop_var_count > 0)
+ has_vars = get_loop_var_info(cctx, &loopinfo);
+ if (ufunc->uf_def_status == UF_NOT_COMPILED || has_vars)
{
extra = ALLOC_CLEAR_ONE(funcref_extra_T);
if (extra == NULL)
return FAIL;
isn->isn_arg.funcref.fr_extra = extra;
- extra->fre_loop_var_idx = loop_var_idx;
- extra->fre_loop_var_count = loop_var_count;
+ extra->fre_loopvar_info = loopinfo;
}
if (ufunc->uf_def_status == UF_NOT_COMPILED)
extra->fre_func_name = vim_strsave(ufunc->uf_name);
else
isn->isn_arg.funcref.fr_dfunc_idx = ufunc->uf_dfunc_idx;
+
+ // Reserve an extra variable to keep track of the number of closures
+ // created.
cctx->ctx_has_closure = 1;
// If the referenced function is a closure, it may use items further up in
@@ -1252,9 +1255,7 @@ generate_FUNCREF(
generate_NEWFUNC(
cctx_T *cctx,
char_u *lambda_name,
- char_u *func_name,
- short loop_var_idx,
- short loop_var_count)
+ char_u *func_name)
{
isn_T *isn;
int ret = OK;
@@ -1271,11 +1272,14 @@ generate_NEWFUNC(
ret = FAIL;
else
{
+ // Reserve an extra variable to keep track of the number of
+ // closures created.
+ cctx->ctx_has_closure = 1;
+
isn->isn_arg.newfunc.nf_arg = arg;
arg->nfa_lambda = lambda_name;
arg->nfa_global = func_name;
- arg->nfa_loop_var_idx = loop_var_idx;
- arg->nfa_loop_var_count = loop_var_count;
+ (void)get_loop_var_info(cctx, &arg->nfa_loopvar_info);
return OK;
}
}
@@ -1371,27 +1375,25 @@ generate_FOR(cctx_T *cctx, int loop_idx)
RETURN_OK_IF_SKIP(cctx);
if ((isn = generate_instr(cctx, ISN_FOR)) == NULL)
return FAIL;
- isn->isn_arg.forloop.for_idx = loop_idx;
+ isn->isn_arg.forloop.for_loop_idx = loop_idx;
// type doesn't matter, will be stored next
return push_type_stack(cctx, &t_any);
}
int
-generate_ENDLOOP(
- cctx_T *cctx,
- int funcref_idx,
- int prev_local_count)
+generate_ENDLOOP(cctx_T *cctx, loop_info_T *loop_info)
{
isn_T *isn;
RETURN_OK_IF_SKIP(cctx);
if ((isn = generate_instr(cctx, ISN_ENDLOOP)) == NULL)
return FAIL;
- isn->isn_arg.endloop.end_funcref_idx = funcref_idx;
- isn->isn_arg.endloop.end_var_idx = prev_local_count;
+ isn->isn_arg.endloop.end_depth = loop_info->li_depth;
+ isn->isn_arg.endloop.end_funcref_idx = loop_info->li_funcref_idx;
+ isn->isn_arg.endloop.end_var_idx = loop_info->li_local_count;
isn->isn_arg.endloop.end_var_count =
- cctx->ctx_locals.ga_len - prev_local_count;
+ cctx->ctx_locals.ga_len - loop_info->li_local_count;
return OK;
}