]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.1.1614: Vim9: possible variable type change v9.1.1614
authorYegappan Lakshmanan <yegappan@yahoo.com>
Sat, 9 Aug 2025 21:52:07 +0000 (23:52 +0200)
committerChristian Brabandt <cb@256bit.org>
Sat, 9 Aug 2025 21:55:34 +0000 (23:55 +0200)
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 <yegappan@yahoo.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
src/testdir/test_vim9_disassemble.vim
src/testdir/test_vim9_script.vim
src/version.c
src/vim9cmds.c
src/vim9execute.c

index 04b5e1118a4c39fbf3db112a63be4e6b820e573d..c05381fb167ab32fe6ac093691af519b51493b3d 100644 (file)
@@ -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
index 76fc36eb1c5f814ff04bf9d230d3ed9e86072083..8109395849aab22023c85ebc32aa2dabae73c84b 100644 (file)
@@ -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:'])
index 9cef88b6d77f896fb73757a525845fa65dd77881..e14ed63caee91c56821d05008fa407eea83d499b 100644 (file)
@@ -719,6 +719,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1614,
 /**/
     1613,
 /**/
index 4486213adf40035421fbb4c4d84769cc85f8aa07..da57912ad710712f3c1cf1f8e63207ad371ca148 100644 (file)
@@ -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
index 9d5709e2574c47e4e20496e141c9b317ee261f30..1787789e3628f1937831cb8f8a022d9a7822a084 100644 (file)
@@ -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);