Skip to content

Commit f56f490

Browse files
yegappanchrisbra
authored andcommitted
patch 9.1.1614: Vim9: possible variable type change
Problem: Vim9: possible variable type change when using closure in a for loop (Maxim Kim) Solution: Use unwind_locals(..., TRUE) (Yegappan Lakshmanan) fixes: #17844 closes: #17951 Signed-off-by: Yegappan Lakshmanan <[email protected]> Signed-off-by: Christian Brabandt <[email protected]>
1 parent a2bb21a commit f56f490

5 files changed

Lines changed: 101 additions & 3 deletions

File tree

src/testdir/test_vim9_disassemble.vim

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4002,4 +4002,71 @@ def Test_disassemble_has_shortcircuit()
40024002
'1 RETURN', g:instr)
40034003
enddef
40044004

4005+
" Disassemble the code generated for a loop with closure following another loop
4006+
def Test_disassemble_loop_with_closure_after_loop()
4007+
var lines =<< trim END
4008+
vim9script
4009+
def Fn()
4010+
for i in "a"
4011+
var v1 = 0
4012+
endfor
4013+
var idx = 1
4014+
while idx > 0
4015+
idx -= 1
4016+
endwhile
4017+
var s = "abc"
4018+
for j in range(2)
4019+
var k = 0
4020+
g:Ref = () => j
4021+
endfor
4022+
enddef
4023+
g:instr = execute('disassemble Fn')
4024+
END
4025+
v9.CheckScriptSuccess(lines)
4026+
assert_match('<SNR>\d\+_Fn\_s*' ..
4027+
'for i in "a"\_s*' ..
4028+
'0 STORE -1 in $0\_s*' ..
4029+
'1 PUSHS "a"\_s*' ..
4030+
'2 FOR $0 -> 6\_s*' ..
4031+
'3 STORE $2\_s*' ..
4032+
'var v1 = 0\_s*' ..
4033+
'4 STORE 0 in $3\_s*' ..
4034+
'endfor\_s*' ..
4035+
'5 JUMP -> 2\_s*' ..
4036+
'6 DROP\_s*' ..
4037+
'var idx = 1\_s*' ..
4038+
'7 STORE 1 in $4\_s*' ..
4039+
'while idx > 0\_s*' ..
4040+
'8 LOAD $4\_s*' ..
4041+
'9 PUSHNR 0\_s*' ..
4042+
'10 COMPARENR >\_s*' ..
4043+
'11 WHILE $5 -> 17\_s*' ..
4044+
'idx -= 1\_s*' ..
4045+
'12 LOAD $4\_s*' ..
4046+
'13 PUSHNR 1\_s*' ..
4047+
'14 OPNR -\_s*' ..
4048+
'15 STORE $4\_s*' ..
4049+
'endwhile\_s*' ..
4050+
'16 JUMP -> 8\_s*' ..
4051+
'var s = "abc"\_s*' ..
4052+
'17 PUSHS "abc"\_s*' ..
4053+
'18 STORE $6\_s*' ..
4054+
'for j in range(2)\_s*' ..
4055+
'19 STORE -1 in $7\_s*' ..
4056+
'20 PUSHNR 2\_s*' ..
4057+
'21 BCALL range(argc 1)\_s*' ..
4058+
'22 FOR $7 -> 29\_s*' ..
4059+
'23 STORE $9\_s*' ..
4060+
'var k = 0\_s*' ..
4061+
'24 STORE 0 in $10\_s*' ..
4062+
'g:Ref = () => j\_s*' ..
4063+
'25 FUNCREF <lambda>\d\+ vars $10-$10\_s*' ..
4064+
'26 STOREG g:Ref\_s*' ..
4065+
'endfor\_s*' ..
4066+
'27 ENDLOOP ref $8 save $10-$10 depth 0\_s*' ..
4067+
'28 JUMP -> 22\_s*' ..
4068+
'29 DROP\_s*' ..
4069+
'30 RETURN void', g:instr)
4070+
enddef
4071+
40054072
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker

src/testdir/test_vim9_script.vim

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2832,6 +2832,35 @@ def Test_define_global_closure_in_loops()
28322832
delfunc g:Global_2c
28332833
enddef
28342834

2835+
" Test for using a closure in a for loop after another for/while loop
2836+
def Test_for_loop_with_closure_after_another_loop()
2837+
var lines =<< trim END
2838+
vim9script
2839+
def Fn()
2840+
# first loop with a local variable
2841+
for i in 'a'
2842+
var v1 = 0
2843+
endfor
2844+
var idx = 1
2845+
while idx > 0
2846+
idx -= 1
2847+
endwhile
2848+
var results = []
2849+
var s = 'abc'
2850+
# second loop with a local variable and a funcref
2851+
for j in range(2)
2852+
var k = 0
2853+
results->add(s)
2854+
g:FuncRefs = () => j
2855+
endfor
2856+
assert_equal(['abc', 'abc'], results)
2857+
enddef
2858+
Fn()
2859+
END
2860+
v9.CheckScriptSuccess(lines)
2861+
unlet g:FuncRefs
2862+
enddef
2863+
28352864
def Test_for_loop_fails()
28362865
v9.CheckDefAndScriptFailure(['for '], ['E1097:', 'E690:'])
28372866
v9.CheckDefAndScriptFailure(['for x'], ['E1097:', 'E690:'])

src/version.c

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

720720
static int included_patches[] =
721721
{ /* Add new patch number below this line */
722+
/**/
723+
1614,
722724
/**/
723725
1613,
724726
/**/

src/vim9cmds.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1252,7 +1252,7 @@ compile_endfor(char_u *arg, cctx_T *cctx)
12521252
if (compile_loop_end(&forscope->fs_loop_info, cctx) == FAIL)
12531253
return NULL;
12541254

1255-
unwind_locals(cctx, scope->se_local_count, FALSE);
1255+
unwind_locals(cctx, scope->se_local_count, TRUE);
12561256

12571257
// At end of ":for" scope jump back to the FOR instruction.
12581258
generate_JUMP(cctx, JUMP_ALWAYS, forscope->fs_top_label);
@@ -1379,7 +1379,7 @@ compile_endwhile(char_u *arg, cctx_T *cctx)
13791379
if (compile_loop_end(&whilescope->ws_loop_info, cctx) == FAIL)
13801380
return NULL;
13811381

1382-
unwind_locals(cctx, scope->se_local_count, FALSE);
1382+
unwind_locals(cctx, scope->se_local_count, TRUE);
13831383

13841384
#ifdef FEAT_PROFILE
13851385
// count the endwhile before jumping

src/vim9execute.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4510,7 +4510,7 @@ exec_instructions(ectx_T *ectx)
45104510
tv->vval.v_number = iptr->isn_arg.storenr.stnr_val;
45114511
break;
45124512

4513-
// Store a value in a list, dict, blob or object variable.
4513+
// Store a value in a list, tuple, dict, blob or object variable.
45144514
case ISN_STOREINDEX:
45154515
{
45164516
int res = execute_storeindex(iptr, ectx);

0 commit comments

Comments
 (0)