Problem: Vim9: crash when using funcref with closure.
Solution: Keep a reference to the funcref that has the outer context.
(closes #9716)
// "out_up" is no longer used, decrement refcount on partial that owns it.
partial_unref(pt->pt_outer.out_up_partial);
+ // Using pt_outer from another partial.
+ partial_unref(pt->pt_outer_partial);
+
// Decrease the reference count for the context of a closure. If down
// to the minimum it may be time to free it.
if (pt->pt_funcstack != NULL)
}
if (arg_pt != NULL)
- pt->pt_outer = arg_pt->pt_outer;
+ {
+ pt->pt_outer_partial = arg_pt;
+ ++arg_pt->pt_refcount;
+ }
}
rettv->v_type = VAR_PARTIAL;
rettv->vval.v_partial = pt;
// For a compiled closure: the arguments and local variables scope
outer_T pt_outer;
+ // For a partial of a partial: use pt_outer values of this partial.
+ partial_T *pt_outer_partial;
+
funcstack_T *pt_funcstack; // copy of stack, used after context
// function returns
unlet g:result_one g:result_two
enddef
+def Test_nested_closure_in_dict()
+ var lines =<< trim END
+ vim9script
+ def Func(): dict<any>
+ var n: number
+ def Inc(): number
+ ++n
+ return n
+ enddef
+ return {inc: function(Inc)}
+ enddef
+ disas Func
+ var d = Func()
+ assert_equal(1, d.inc())
+ assert_equal(2, d.inc())
+ END
+ v9.CheckScriptSuccess(lines)
+enddef
+
def Test_check_func_arg_types()
var lines =<< trim END
vim9script
static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 4322,
/**/
4321,
/**/
dict_stack_drop();
}
+/*
+ * Get a pointer to useful "pt_outer" of "pt".
+ */
+ static outer_T *
+get_pt_outer(partial_T *pt)
+{
+ partial_T *ptref = pt->pt_outer_partial;
+
+ if (ptref == NULL)
+ return &pt->pt_outer;
+
+ // partial using partial (recursively)
+ while (ptref->pt_outer_partial != NULL)
+ ptref = ptref->pt_outer_partial;
+ return &ptref->pt_outer;
+}
+
/*
* Call compiled function "cdf_idx" from compiled code.
* This adds a stack frame and sets the instruction pointer to the start of the
return FAIL;
if (pt != NULL)
{
- ref->or_outer = &pt->pt_outer;
+ ref->or_outer = get_pt_outer(pt);
++pt->pt_refcount;
ref->or_partial = pt;
}
else if (ufunc->uf_partial != NULL)
{
- ref->or_outer = &ufunc->uf_partial->pt_outer;
+ ref->or_outer = get_pt_outer(ufunc->uf_partial);
++ufunc->uf_partial->pt_refcount;
ref->or_partial = ufunc->uf_partial;
}
goto failed_early;
if (partial != NULL)
{
- if (partial->pt_outer.out_stack == NULL)
+ outer_T *outer = get_pt_outer(partial);
+
+ if (outer->out_stack == NULL)
{
if (current_ectx != NULL)
{
}
else
{
- ectx.ec_outer_ref->or_outer = &partial->pt_outer;
+ ectx.ec_outer_ref->or_outer = outer;
++partial->pt_refcount;
ectx.ec_outer_ref->or_partial = partial;
}