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:
@@ -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;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user