patch 9.1.1614: Vim9: possible variable type change Commit: https://github.com/vim/vim/commit/f56f490ca2bcc79e933cbb9fefb19d5e4e06d481 Author: Yegappan Lakshmanan <yegap...@yahoo.com> 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 <yegap...@yahoo.com> Signed-off-by: Christian Brabandt <c...@256bit.org> 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 vim_dev+unsubscr...@googlegroups.com. To view this discussion visit https://groups.google.com/d/msgid/vim_dev/E1ukrbp-005CYP-Jo%40256bit.org.