mirror of
https://github.com/vim/vim.git
synced 2025-09-23 03:43:49 -04:00
patch 8.2.0703: Vim9: closure cannot store value in outer context
Problem: Vim9: closure cannot store value in outer context. Solution: Make storing value in outer context work. Make :disassemble accept a function reference.
This commit is contained in:
@@ -4337,9 +4337,11 @@ set_ref_in_item(
|
|||||||
partial_T *pt = tv->vval.v_partial;
|
partial_T *pt = tv->vval.v_partial;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
// A partial does not have a copyID, because it cannot contain itself.
|
if (pt != NULL && pt->pt_copyID != copyID)
|
||||||
if (pt != NULL)
|
|
||||||
{
|
{
|
||||||
|
// Didn't see this partial yet.
|
||||||
|
pt->pt_copyID = copyID;
|
||||||
|
|
||||||
abort = set_ref_in_func(pt->pt_name, pt->pt_func, copyID);
|
abort = set_ref_in_func(pt->pt_name, pt->pt_func, copyID);
|
||||||
|
|
||||||
if (pt->pt_dict != NULL)
|
if (pt->pt_dict != NULL)
|
||||||
|
@@ -1812,6 +1812,7 @@ struct partial_S
|
|||||||
typval_T *pt_argv; // arguments in allocated array
|
typval_T *pt_argv; // arguments in allocated array
|
||||||
|
|
||||||
dict_T *pt_dict; // dict for "self"
|
dict_T *pt_dict; // dict for "self"
|
||||||
|
int pt_copyID; // funcstack may contain pointer to partial
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct AutoPatCmd_S AutoPatCmd;
|
typedef struct AutoPatCmd_S AutoPatCmd;
|
||||||
|
@@ -291,6 +291,42 @@ def Test_disassemble_call()
|
|||||||
res)
|
res)
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
|
def s:CreateRefs()
|
||||||
|
let local = 'a'
|
||||||
|
def Append(arg: string)
|
||||||
|
local ..= arg
|
||||||
|
enddef
|
||||||
|
g:Append = Append
|
||||||
|
def Get(): string
|
||||||
|
return local
|
||||||
|
enddef
|
||||||
|
g:Get = Get
|
||||||
|
enddef
|
||||||
|
|
||||||
|
def Test_disassemble_closure()
|
||||||
|
CreateRefs()
|
||||||
|
let res = execute('disass g:Append')
|
||||||
|
assert_match('<lambda>\d.*' ..
|
||||||
|
'local ..= arg.*' ..
|
||||||
|
'\d LOADOUTER $0.*' ..
|
||||||
|
'\d LOAD arg\[-1\].*' ..
|
||||||
|
'\d CONCAT.*' ..
|
||||||
|
'\d STOREOUTER $0.*' ..
|
||||||
|
'\d PUSHNR 0.*' ..
|
||||||
|
'\d RETURN.*',
|
||||||
|
res)
|
||||||
|
|
||||||
|
res = execute('disass g:Get')
|
||||||
|
assert_match('<lambda>\d.*' ..
|
||||||
|
'return local.*' ..
|
||||||
|
'\d LOADOUTER $0.*' ..
|
||||||
|
'\d RETURN.*',
|
||||||
|
res)
|
||||||
|
|
||||||
|
unlet g:Append
|
||||||
|
unlet g:Get
|
||||||
|
enddef
|
||||||
|
|
||||||
|
|
||||||
def EchoArg(arg: string): string
|
def EchoArg(arg: string): string
|
||||||
return arg
|
return arg
|
||||||
|
@@ -738,6 +738,32 @@ def Test_closure_using_argument()
|
|||||||
unlet g:UseVararg
|
unlet g:UseVararg
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
|
def MakeGetAndAppendRefs()
|
||||||
|
let local = 'a'
|
||||||
|
|
||||||
|
def Append(arg: string)
|
||||||
|
local ..= arg
|
||||||
|
enddef
|
||||||
|
g:Append = Append
|
||||||
|
|
||||||
|
def Get(): string
|
||||||
|
return local
|
||||||
|
enddef
|
||||||
|
g:Get = Get
|
||||||
|
enddef
|
||||||
|
|
||||||
|
def Test_closure_append_get()
|
||||||
|
MakeGetAndAppendRefs()
|
||||||
|
assert_equal('a', g:Get())
|
||||||
|
g:Append('-b')
|
||||||
|
assert_equal('a-b', g:Get())
|
||||||
|
g:Append('-c')
|
||||||
|
assert_equal('a-b-c', g:Get())
|
||||||
|
|
||||||
|
unlet g:Append
|
||||||
|
unlet g:Get
|
||||||
|
enddef
|
||||||
|
|
||||||
def Test_nested_closure()
|
def Test_nested_closure()
|
||||||
let local = 'text'
|
let local = 'text'
|
||||||
def Closure(arg: string): string
|
def Closure(arg: string): string
|
||||||
|
@@ -746,6 +746,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
703,
|
||||||
/**/
|
/**/
|
||||||
702,
|
702,
|
||||||
/**/
|
/**/
|
||||||
|
@@ -40,8 +40,9 @@ typedef enum {
|
|||||||
ISN_STOREW, // pop into window-local variable isn_arg.string
|
ISN_STOREW, // pop into window-local variable isn_arg.string
|
||||||
ISN_STORET, // pop into tab-local variable isn_arg.string
|
ISN_STORET, // pop into tab-local variable isn_arg.string
|
||||||
ISN_STORES, // pop into script variable isn_arg.loadstore
|
ISN_STORES, // pop into script variable isn_arg.loadstore
|
||||||
|
ISN_STOREOUTER, // pop variable into outer scope isn_arg.number
|
||||||
ISN_STORESCRIPT, // pop into script variable isn_arg.script
|
ISN_STORESCRIPT, // pop into script variable isn_arg.script
|
||||||
ISN_STOREOPT, // pop into option isn_arg.string
|
ISN_STOREOPT, // pop into option isn_arg.string
|
||||||
ISN_STOREENV, // pop into environment variable isn_arg.string
|
ISN_STOREENV, // pop into environment variable isn_arg.string
|
||||||
ISN_STOREREG, // pop into register isn_arg.number
|
ISN_STOREREG, // pop into register isn_arg.number
|
||||||
// ISN_STOREOTHER, // pop into other script variable isn_arg.other.
|
// ISN_STOREOTHER, // pop into other script variable isn_arg.other.
|
||||||
|
@@ -4496,7 +4496,11 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
|||||||
generate_LOADV(cctx, name + 2, TRUE);
|
generate_LOADV(cctx, name + 2, TRUE);
|
||||||
break;
|
break;
|
||||||
case dest_local:
|
case dest_local:
|
||||||
generate_LOAD(cctx, ISN_LOAD, lvar->lv_idx, NULL, type);
|
if (lvar->lv_from_outer)
|
||||||
|
generate_LOAD(cctx, ISN_LOADOUTER, lvar->lv_idx,
|
||||||
|
NULL, type);
|
||||||
|
else
|
||||||
|
generate_LOAD(cctx, ISN_LOAD, lvar->lv_idx, NULL, type);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4713,8 +4717,8 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
|||||||
|
|
||||||
// optimization: turn "var = 123" from ISN_PUSHNR + ISN_STORE
|
// optimization: turn "var = 123" from ISN_PUSHNR + ISN_STORE
|
||||||
// into ISN_STORENR
|
// into ISN_STORENR
|
||||||
if (instr->ga_len == instr_count + 1
|
if (!lvar->lv_from_outer && instr->ga_len == instr_count + 1
|
||||||
&& isn->isn_type == ISN_PUSHNR)
|
&& isn->isn_type == ISN_PUSHNR)
|
||||||
{
|
{
|
||||||
varnumber_T val = isn->isn_arg.number;
|
varnumber_T val = isn->isn_arg.number;
|
||||||
garray_T *stack = &cctx->ctx_type_stack;
|
garray_T *stack = &cctx->ctx_type_stack;
|
||||||
@@ -4725,6 +4729,8 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
|||||||
if (stack->ga_len > 0)
|
if (stack->ga_len > 0)
|
||||||
--stack->ga_len;
|
--stack->ga_len;
|
||||||
}
|
}
|
||||||
|
else if (lvar->lv_from_outer)
|
||||||
|
generate_STORE(cctx, ISN_STOREOUTER, lvar->lv_idx, NULL);
|
||||||
else
|
else
|
||||||
generate_STORE(cctx, ISN_STORE, lvar->lv_idx, NULL);
|
generate_STORE(cctx, ISN_STORE, lvar->lv_idx, NULL);
|
||||||
}
|
}
|
||||||
@@ -6686,6 +6692,7 @@ delete_instr(isn_T *isn)
|
|||||||
case ISN_PUSHSPEC:
|
case ISN_PUSHSPEC:
|
||||||
case ISN_RETURN:
|
case ISN_RETURN:
|
||||||
case ISN_STORE:
|
case ISN_STORE:
|
||||||
|
case ISN_STOREOUTER:
|
||||||
case ISN_STOREV:
|
case ISN_STOREV:
|
||||||
case ISN_STORENR:
|
case ISN_STORENR:
|
||||||
case ISN_STOREREG:
|
case ISN_STOREREG:
|
||||||
|
@@ -1070,6 +1070,14 @@ call_def_function(
|
|||||||
*tv = *STACK_TV_BOT(0);
|
*tv = *STACK_TV_BOT(0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// store variable or argument in outer scope
|
||||||
|
case ISN_STOREOUTER:
|
||||||
|
--ectx.ec_stack.ga_len;
|
||||||
|
tv = STACK_OUT_TV_VAR(iptr->isn_arg.number);
|
||||||
|
clear_tv(tv);
|
||||||
|
*tv = *STACK_TV_BOT(0);
|
||||||
|
break;
|
||||||
|
|
||||||
// store s: variable in old script
|
// store s: variable in old script
|
||||||
case ISN_STORES:
|
case ISN_STORES:
|
||||||
{
|
{
|
||||||
@@ -2133,7 +2141,7 @@ ex_disassemble(exarg_T *eap)
|
|||||||
int is_global = FALSE;
|
int is_global = FALSE;
|
||||||
|
|
||||||
fname = trans_function_name(&arg, &is_global, FALSE,
|
fname = trans_function_name(&arg, &is_global, FALSE,
|
||||||
TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
|
TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD, NULL, NULL);
|
||||||
if (fname == NULL)
|
if (fname == NULL)
|
||||||
{
|
{
|
||||||
semsg(_(e_invarg2), eap->arg);
|
semsg(_(e_invarg2), eap->arg);
|
||||||
@@ -2275,12 +2283,17 @@ ex_disassemble(exarg_T *eap)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case ISN_STORE:
|
case ISN_STORE:
|
||||||
|
case ISN_STOREOUTER:
|
||||||
|
{
|
||||||
|
char *add = iptr->isn_type == ISN_STORE ? "" : "OUTER";
|
||||||
|
|
||||||
if (iptr->isn_arg.number < 0)
|
if (iptr->isn_arg.number < 0)
|
||||||
smsg("%4d STORE arg[%lld]", current,
|
smsg("%4d STORE%s arg[%lld]", current, add,
|
||||||
(long long)(iptr->isn_arg.number + STACK_FRAME_SIZE));
|
(long long)(iptr->isn_arg.number + STACK_FRAME_SIZE));
|
||||||
else
|
else
|
||||||
smsg("%4d STORE $%lld", current,
|
smsg("%4d STORE%s $%lld", current, add,
|
||||||
(long long)(iptr->isn_arg.number));
|
(long long)(iptr->isn_arg.number));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case ISN_STOREV:
|
case ISN_STOREV:
|
||||||
smsg("%4d STOREV v:%s", current,
|
smsg("%4d STOREV v:%s", current,
|
||||||
|
Reference in New Issue
Block a user