Skip to content

Commit f3eac69

Browse files
yegappanchrisbra
authored andcommitted
patch 9.0.2038: Vim9: object method funcref not cleaned up after use
Problem: Vim9: object method funcref not cleaned up after use Solution: Clean up type stack after using object method funcref, remove now longer used ISN_DEFEROBJ instrunction closes: #13360 Signed-off-by: Christian Brabandt <[email protected]> Co-authored-by: Yegappan Lakshmanan <[email protected]>
1 parent 209ec90 commit f3eac69

File tree

9 files changed

+276
-45
lines changed

9 files changed

+276
-45
lines changed

src/proto/vim9instr.pro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ int generate_CALL(cctx_T *cctx, ufunc_T *ufunc, class_T *cl, int mi, int pushed_
6262
int generate_UCALL(cctx_T *cctx, char_u *name, int argcount);
6363
int check_func_args_from_type(cctx_T *cctx, type_T *type, int argcount, int at_top, char_u *name);
6464
int generate_PCALL(cctx_T *cctx, int argcount, char_u *name, type_T *type, int at_top);
65-
int generate_DEFER(cctx_T *cctx, int var_idx, int obj_method, int argcount);
65+
int generate_DEFER(cctx_T *cctx, int var_idx, int argcount);
6666
int generate_STRINGMEMBER(cctx_T *cctx, char_u *name, size_t len);
6767
int generate_ECHO(cctx_T *cctx, int with_white, int count);
6868
int generate_MULT_EXPR(cctx_T *cctx, isntype_T isn_type, int count);

src/testdir/test_vim9_class.vim

Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8022,4 +8022,256 @@ def Test_class_member_funcref()
80228022
v9.CheckSourceSuccess(lines)
80238023
enddef
80248024

8025+
" Test for using object methods as popup callback functions
8026+
def Test_objmethod_popup_callback()
8027+
# Use the popup from the script level
8028+
var lines =<< trim END
8029+
vim9script
8030+
8031+
class A
8032+
this.selection: number = -1
8033+
this.filterkeys: list<string> = []
8034+
8035+
def PopupFilter(id: number, key: string): bool
8036+
add(this.filterkeys, key)
8037+
return popup_filter_yesno(id, key)
8038+
enddef
8039+
8040+
def PopupCb(id: number, result: number)
8041+
this.selection = result ? 100 : 200
8042+
enddef
8043+
endclass
8044+
8045+
var a = A.new()
8046+
feedkeys('', 'xt')
8047+
var winid = popup_create('Y/N?',
8048+
{filter: a.PopupFilter, callback: a.PopupCb})
8049+
feedkeys('y', 'xt')
8050+
popup_close(winid)
8051+
assert_equal(100, a.selection)
8052+
assert_equal(['y'], a.filterkeys)
8053+
feedkeys('', 'xt')
8054+
winid = popup_create('Y/N?',
8055+
{filter: a.PopupFilter, callback: a.PopupCb})
8056+
feedkeys('n', 'xt')
8057+
popup_close(winid)
8058+
assert_equal(200, a.selection)
8059+
assert_equal(['y', 'n'], a.filterkeys)
8060+
END
8061+
v9.CheckSourceSuccess(lines)
8062+
8063+
# Use the popup from a def function
8064+
lines =<< trim END
8065+
vim9script
8066+
8067+
class A
8068+
this.selection: number = -1
8069+
this.filterkeys: list<string> = []
8070+
8071+
def PopupFilter(id: number, key: string): bool
8072+
add(this.filterkeys, key)
8073+
return popup_filter_yesno(id, key)
8074+
enddef
8075+
8076+
def PopupCb(id: number, result: number)
8077+
this.selection = result ? 100 : 200
8078+
enddef
8079+
endclass
8080+
8081+
def Foo()
8082+
var a = A.new()
8083+
feedkeys('', 'xt')
8084+
var winid = popup_create('Y/N?',
8085+
{filter: a.PopupFilter, callback: a.PopupCb})
8086+
feedkeys('y', 'xt')
8087+
popup_close(winid)
8088+
assert_equal(100, a.selection)
8089+
assert_equal(['y'], a.filterkeys)
8090+
feedkeys('', 'xt')
8091+
winid = popup_create('Y/N?',
8092+
{filter: a.PopupFilter, callback: a.PopupCb})
8093+
feedkeys('n', 'xt')
8094+
popup_close(winid)
8095+
assert_equal(200, a.selection)
8096+
assert_equal(['y', 'n'], a.filterkeys)
8097+
enddef
8098+
Foo()
8099+
END
8100+
v9.CheckSourceSuccess(lines)
8101+
enddef
8102+
8103+
" Test for using class methods as popup callback functions
8104+
def Test_classmethod_popup_callback()
8105+
# Use the popup from the script level
8106+
var lines =<< trim END
8107+
vim9script
8108+
8109+
class A
8110+
static selection: number = -1
8111+
static filterkeys: list<string> = []
8112+
8113+
static def PopupFilter(id: number, key: string): bool
8114+
add(filterkeys, key)
8115+
return popup_filter_yesno(id, key)
8116+
enddef
8117+
8118+
static def PopupCb(id: number, result: number)
8119+
selection = result ? 100 : 200
8120+
enddef
8121+
endclass
8122+
8123+
feedkeys('', 'xt')
8124+
var winid = popup_create('Y/N?',
8125+
{filter: A.PopupFilter, callback: A.PopupCb})
8126+
feedkeys('y', 'xt')
8127+
popup_close(winid)
8128+
assert_equal(100, A.selection)
8129+
assert_equal(['y'], A.filterkeys)
8130+
feedkeys('', 'xt')
8131+
winid = popup_create('Y/N?',
8132+
{filter: A.PopupFilter, callback: A.PopupCb})
8133+
feedkeys('n', 'xt')
8134+
popup_close(winid)
8135+
assert_equal(200, A.selection)
8136+
assert_equal(['y', 'n'], A.filterkeys)
8137+
END
8138+
v9.CheckSourceSuccess(lines)
8139+
8140+
# Use the popup from a def function
8141+
lines =<< trim END
8142+
vim9script
8143+
8144+
class A
8145+
static selection: number = -1
8146+
static filterkeys: list<string> = []
8147+
8148+
static def PopupFilter(id: number, key: string): bool
8149+
add(filterkeys, key)
8150+
return popup_filter_yesno(id, key)
8151+
enddef
8152+
8153+
static def PopupCb(id: number, result: number)
8154+
selection = result ? 100 : 200
8155+
enddef
8156+
endclass
8157+
8158+
def Foo()
8159+
feedkeys('', 'xt')
8160+
var winid = popup_create('Y/N?',
8161+
{filter: A.PopupFilter, callback: A.PopupCb})
8162+
feedkeys('y', 'xt')
8163+
popup_close(winid)
8164+
assert_equal(100, A.selection)
8165+
assert_equal(['y'], A.filterkeys)
8166+
feedkeys('', 'xt')
8167+
winid = popup_create('Y/N?',
8168+
{filter: A.PopupFilter, callback: A.PopupCb})
8169+
feedkeys('n', 'xt')
8170+
popup_close(winid)
8171+
assert_equal(200, A.selection)
8172+
assert_equal(['y', 'n'], A.filterkeys)
8173+
enddef
8174+
Foo()
8175+
END
8176+
v9.CheckSourceSuccess(lines)
8177+
enddef
8178+
8179+
" Test for using an object method as a timer callback function
8180+
def Test_objmethod_timer_callback()
8181+
# Use the timer callback from script level
8182+
var lines =<< trim END
8183+
vim9script
8184+
8185+
class A
8186+
this.timerTick: number = -1
8187+
def TimerCb(timerID: number)
8188+
this.timerTick = 6
8189+
enddef
8190+
endclass
8191+
8192+
var a = A.new()
8193+
timer_start(0, a.TimerCb)
8194+
var maxWait = 5
8195+
while maxWait > 0 && a.timerTick == -1
8196+
:sleep 10m
8197+
maxWait -= 1
8198+
endwhile
8199+
assert_equal(6, a.timerTick)
8200+
END
8201+
v9.CheckSourceSuccess(lines)
8202+
8203+
# Use the timer callback from a def function
8204+
lines =<< trim END
8205+
vim9script
8206+
8207+
class A
8208+
this.timerTick: number = -1
8209+
def TimerCb(timerID: number)
8210+
this.timerTick = 6
8211+
enddef
8212+
endclass
8213+
8214+
def Foo()
8215+
var a = A.new()
8216+
timer_start(0, a.TimerCb)
8217+
var maxWait = 5
8218+
while maxWait > 0 && a.timerTick == -1
8219+
:sleep 10m
8220+
maxWait -= 1
8221+
endwhile
8222+
assert_equal(6, a.timerTick)
8223+
enddef
8224+
Foo()
8225+
END
8226+
v9.CheckSourceSuccess(lines)
8227+
enddef
8228+
8229+
" Test for using a class method as a timer callback function
8230+
def Test_classmethod_timer_callback()
8231+
# Use the timer callback from script level
8232+
var lines =<< trim END
8233+
vim9script
8234+
8235+
class A
8236+
static timerTick: number = -1
8237+
static def TimerCb(timerID: number)
8238+
timerTick = 6
8239+
enddef
8240+
endclass
8241+
8242+
timer_start(0, A.TimerCb)
8243+
var maxWait = 5
8244+
while maxWait > 0 && A.timerTick == -1
8245+
:sleep 10m
8246+
maxWait -= 1
8247+
endwhile
8248+
assert_equal(6, A.timerTick)
8249+
END
8250+
v9.CheckSourceSuccess(lines)
8251+
8252+
# Use the timer callback from a def function
8253+
lines =<< trim END
8254+
vim9script
8255+
8256+
class A
8257+
static timerTick: number = -1
8258+
static def TimerCb(timerID: number)
8259+
timerTick = 6
8260+
enddef
8261+
endclass
8262+
8263+
def Foo()
8264+
timer_start(0, A.TimerCb)
8265+
var maxWait = 5
8266+
while maxWait > 0 && A.timerTick == -1
8267+
:sleep 10m
8268+
maxWait -= 1
8269+
endwhile
8270+
assert_equal(6, A.timerTick)
8271+
enddef
8272+
Foo()
8273+
END
8274+
v9.CheckSourceSuccess(lines)
8275+
enddef
8276+
80258277
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker

src/testdir/test_vim9_disassemble.vim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3276,7 +3276,7 @@ def Test_funcref_with_class()
32763276
'defer a.Foo()\_s*' ..
32773277
'0 LOAD arg\[-1\]\_s*' ..
32783278
'1 FUNCREF A.Foo\_s*' ..
3279-
'2 DEFEROBJ 0 args\_s*' ..
3279+
'2 DEFER 0 args\_s*' ..
32803280
'3 RETURN void', g:instr)
32813281
unlet g:instr
32823282
enddef

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -704,6 +704,8 @@ static char *(features[]) =
704704

705705
static int included_patches[] =
706706
{ /* Add new patch number below this line */
707+
/**/
708+
2038,
707709
/**/
708710
2037,
709711
/**/

src/vim9.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,6 @@ typedef enum {
125125
ISN_NEWFUNC, // create a global function from a lambda function
126126
ISN_DEF, // list functions
127127
ISN_DEFER, // :defer argument count is isn_arg.number
128-
ISN_DEFEROBJ, // idem, function is an object method
129128

130129
// expression operations
131130
ISN_JUMP, // jump if condition is matched isn_arg.jump

src/vim9cmds.c

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2000,7 +2000,6 @@ compile_defer(char_u *arg_start, cctx_T *cctx)
20002000
int defer_var_idx;
20012001
type_T *type;
20022002
int func_idx;
2003-
int obj_method = 0;
20042003

20052004
// Get a funcref for the function name.
20062005
// TODO: better way to find the "(".
@@ -2016,15 +2015,8 @@ compile_defer(char_u *arg_start, cctx_T *cctx)
20162015
// TODO: better type
20172016
generate_PUSHFUNC(cctx, (char_u *)internal_func_name(func_idx),
20182017
&t_func_any, FALSE);
2019-
else
2020-
{
2021-
int typecount = cctx->ctx_type_stack.ga_len;
2022-
if (compile_expr0(&arg, cctx) == FAIL)
2023-
return NULL;
2024-
if (cctx->ctx_type_stack.ga_len >= typecount + 2)
2025-
// must have seen "obj.Func", pushed an object and a function
2026-
obj_method = 1;
2027-
}
2018+
else if (compile_expr0(&arg, cctx) == FAIL)
2019+
return NULL;
20282020
*paren = '(';
20292021

20302022
// check for function type
@@ -2056,7 +2048,7 @@ compile_defer(char_u *arg_start, cctx_T *cctx)
20562048
defer_var_idx = get_defer_var_idx(cctx);
20572049
if (defer_var_idx == 0)
20582050
return NULL;
2059-
if (generate_DEFER(cctx, defer_var_idx - 1, obj_method, argcount) == FAIL)
2051+
if (generate_DEFER(cctx, defer_var_idx - 1, argcount) == FAIL)
20602052
return NULL;
20612053

20622054
return skipwhite(arg);

0 commit comments

Comments
 (0)