0
0
mirror of https://github.com/vim/vim.git synced 2025-09-23 03:43:49 -04:00

patch 8.2.0679: Vim9: incomplete support for closures

Problem:    Vim9: incomplete support for closures.
Solution:   At the end of a function copy arguments and local variables if
            they are still used by a referenced closure.
This commit is contained in:
Bram Moolenaar
2020-05-02 17:52:42 +02:00
parent d58a662f44
commit bf67ea1af0
6 changed files with 261 additions and 66 deletions

View File

@@ -116,6 +116,9 @@ struct cctx_S {
garray_T ctx_locals; // currently visible local variables
int ctx_locals_count; // total number of local variables
int ctx_closure_count; // number of closures created in the
// function
garray_T ctx_imports; // imported items
int ctx_skip; // when TRUE skip commands, when FALSE skip
@@ -1254,7 +1257,8 @@ generate_FUNCREF(cctx_T *cctx, int dfunc_idx)
RETURN_OK_IF_SKIP(cctx);
if ((isn = generate_instr(cctx, ISN_FUNCREF)) == NULL)
return FAIL;
isn->isn_arg.number = dfunc_idx;
isn->isn_arg.funcref.fr_func = dfunc_idx;
isn->isn_arg.funcref.fr_var_idx = cctx->ctx_closure_count++;
if (ga_grow(stack, 1) == FAIL)
return FAIL;
@@ -6395,6 +6399,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
dfunc->df_instr = instr->ga_data;
dfunc->df_instr_count = instr->ga_len;
dfunc->df_varcount = cctx.ctx_locals_count;
dfunc->df_closure_count = cctx.ctx_closure_count;
if (cctx.ctx_outer_used)
ufunc->uf_flags |= FC_CLOSURE;
}
@@ -6620,6 +6625,23 @@ delete_def_function_contents(dfunc_T *dfunc)
delete_instr(dfunc->df_instr + idx);
VIM_CLEAR(dfunc->df_instr);
}
if (dfunc->df_funcstack != NULL)
{
// Decrease the reference count for the context of a closure. If down
// to zero free it and clear the variables on the stack.
if (--dfunc->df_funcstack->fs_refcount == 0)
{
garray_T *gap = &dfunc->df_funcstack->fs_ga;
typval_T *stack = gap->ga_data;
int i;
for (i = 0; i < gap->ga_len; ++i)
clear_tv(stack + i);
ga_clear(gap);
vim_free(dfunc->df_funcstack);
}
dfunc->df_funcstack = NULL;
}
dfunc->df_deleted = TRUE;
}