patch 9.1.1614: Vim9: possible variable type change
Commit:
https://github.com/vim/vim/commit/f56f490ca2bcc79e933cbb9fefb19d5e4e06d481
Author: Yegappan Lakshmanan <[email protected]>
Date: Sat Aug 9 23:52:07 2025 +0200
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]>
diff --git a/src/testdir/test_vim9_disassemble.vim
b/src/testdir/test_vim9_disassemble.vim
index 04b5e1118..c05381fb1 100644
--- a/src/testdir/test_vim9_disassemble.vim
+++ b/src/testdir/test_vim9_disassemble.vim
@@ -4002,4 +4002,71 @@ def Test_disassemble_has_shortcircuit()
'1 RETURN', g:instr)
enddef
+" Disassemble the code generated for a loop with closure following another loop
+def Test_disassemble_loop_with_closure_after_loop()
+ var lines =<< trim END
+ vim9script
+ def Fn()
+ for i in "a"
+ var v1 = 0
+ endfor
+ var idx = 1
+ while idx > 0
+ idx -= 1
+ endwhile
+ var s = "abc"
+ for j in range(2)
+ var k = 0
+ g:Ref = () => j
+ endfor
+ enddef
+ g:instr = execute('disassemble Fn')
+ END
+ v9.CheckScriptSuccess(lines)
+ assert_match('<SNR>\d\+_Fn\_s*' ..
+ 'for i in "a"\_s*' ..
+ '0 STORE -1 in $0\_s*' ..
+ '1 PUSHS "a"\_s*' ..
+ '2 FOR $0 -> 6\_s*' ..
+ '3 STORE $2\_s*' ..
+ 'var v1 = 0\_s*' ..
+ '4 STORE 0 in $3\_s*' ..
+ 'endfor\_s*' ..
+ '5 JUMP -> 2\_s*' ..
+ '6 DROP\_s*' ..
+ 'var idx = 1\_s*' ..
+ '7 STORE 1 in $4\_s*' ..
+ 'while idx > 0\_s*' ..
+ '8 LOAD $4\_s*' ..
+ '9 PUSHNR 0\_s*' ..
+ '10 COMPARENR >\_s*' ..
+ '11 WHILE $5 -> 17\_s*' ..
+ 'idx -= 1\_s*' ..
+ '12 LOAD $4\_s*' ..
+ '13 PUSHNR 1\_s*' ..
+ '14 OPNR -\_s*' ..
+ '15 STORE $4\_s*' ..
+ 'endwhile\_s*' ..
+ '16 JUMP -> 8\_s*' ..
+ 'var s = "abc"\_s*' ..
+ '17 PUSHS "abc"\_s*' ..
+ '18 STORE $6\_s*' ..
+ 'for j in range(2)\_s*' ..
+ '19 STORE -1 in $7\_s*' ..
+ '20 PUSHNR 2\_s*' ..
+ '21 BCALL range(argc 1)\_s*' ..
+ '22 FOR $7 -> 29\_s*' ..
+ '23 STORE $9\_s*' ..
+ 'var k = 0\_s*' ..
+ '24 STORE 0 in $10\_s*' ..
+ 'g:Ref = () => j\_s*' ..
+ '25 FUNCREF <lambda>\d\+ vars $10-$10\_s*' ..
+ '26 STOREG g:Ref\_s*' ..
+ 'endfor\_s*' ..
+ '27 ENDLOOP ref $8 save $10-$10 depth 0\_s*' ..
+ '28 JUMP -> 22\_s*' ..
+ '29 DROP\_s*' ..
+ '30 RETURN void', g:instr)
+enddef
+
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim
index 76fc36eb1..810939584 100644
--- a/src/testdir/test_vim9_script.vim
+++ b/src/testdir/test_vim9_script.vim
@@ -2832,6 +2832,35 @@ def Test_define_global_closure_in_loops()
delfunc g:Global_2c
enddef
+" Test for using a closure in a for loop after another for/while loop
+def Test_for_loop_with_closure_after_another_loop()
+ var lines =<< trim END
+ vim9script
+ def Fn()
+ # first loop with a local variable
+ for i in 'a'
+ var v1 = 0
+ endfor
+ var idx = 1
+ while idx > 0
+ idx -= 1
+ endwhile
+ var results = []
+ var s = 'abc'
+ # second loop with a local variable and a funcref
+ for j in range(2)
+ var k = 0
+ results->add(s)
+ g:FuncRefs = () => j
+ endfor
+ assert_equal(['abc', 'abc'], results)
+ enddef
+ Fn()
+ END
+ v9.CheckScriptSuccess(lines)
+ unlet g:FuncRefs
+enddef
+
def Test_for_loop_fails()
v9.CheckDefAndScriptFailure(['for '], ['E1097:', 'E690:'])
v9.CheckDefAndScriptFailure(['for x'], ['E1097:', 'E690:'])
diff --git a/src/version.c b/src/version.c
index 9cef88b6d..e14ed63ca 100644
--- a/src/version.c
+++ b/src/version.c
@@ -719,6 +719,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 1614,
/**/
1613,
/**/
diff --git a/src/vim9cmds.c b/src/vim9cmds.c
index 4486213ad..da57912ad 100644
--- a/src/vim9cmds.c
+++ b/src/vim9cmds.c
@@ -1252,7 +1252,7 @@ compile_endfor(char_u *arg, cctx_T *cctx)
if (compile_loop_end(&forscope->fs_loop_info, cctx) == FAIL)
return NULL;
- unwind_locals(cctx, scope->se_local_count, FALSE);
+ unwind_locals(cctx, scope->se_local_count, TRUE);
// At end of ":for" scope jump back to the FOR instruction.
generate_JUMP(cctx, JUMP_ALWAYS, forscope->fs_top_label);
@@ -1379,7 +1379,7 @@ compile_endwhile(char_u *arg, cctx_T *cctx)
if (compile_loop_end(&whilescope->ws_loop_info, cctx) == FAIL)
return NULL;
- unwind_locals(cctx, scope->se_local_count, FALSE);
+ unwind_locals(cctx, scope->se_local_count, TRUE);
#ifdef FEAT_PROFILE
// count the endwhile before jumping
diff --git a/src/vim9execute.c b/src/vim9execute.c
index 9d5709e25..1787789e3 100644
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -4510,7 +4510,7 @@ exec_instructions(ectx_T *ectx)
tv->vval.v_number = iptr->isn_arg.storenr.stnr_val;
break;
- // Store a value in a list, dict, blob or object variable.
+ // Store a value in a list, tuple, dict, blob or object variable.
case ISN_STOREINDEX:
{
int res = execute_storeindex(iptr, ectx);
--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion visit
https://groups.google.com/d/msgid/vim_dev/E1ukrbp-005CYP-Jo%40256bit.org.