0
0
mirror of https://github.com/vim/vim.git synced 2025-09-25 03:54:15 -04:00

patch 9.0.0502: a closure in a nested loop in a :def function does not work

Problem:    A closure in a nested loop in a :def function does not work.
Solution:   Use an array of loopvars, one per loop level.
This commit is contained in:
Bram Moolenaar
2022-09-19 15:54:34 +01:00
parent 18ee0feb5d
commit cc34181f99
15 changed files with 398 additions and 182 deletions

View File

@@ -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;
}