]> granicus.if.org Git - vim/commitdiff
patch 9.0.0459: Vim9: block in for loop doesn't behave like a code block v9.0.0459
authorBram Moolenaar <Bram@vim.org>
Tue, 13 Sep 2022 20:10:45 +0000 (21:10 +0100)
committerBram Moolenaar <Bram@vim.org>
Tue, 13 Sep 2022 20:10:45 +0000 (21:10 +0100)
Problem:    Vim9: block in for loop doesn't behave like a code block.
Solution:   Use a new block ID for each loop at the script level.

src/ex_eval.c
src/testdir/test_vim9_script.vim
src/version.c

index 2f31b3e1c572fe158a4b8adb91a663be57314424..4315c2a62cd4b2d302274eba483697af70da12b5 100644 (file)
@@ -1230,15 +1230,18 @@ ex_while(exarg_T *eap)
            {
                scriptitem_T    *si = SCRIPT_ITEM(current_sctx.sc_sid);
                int             i;
+               int             first;
                int             func_defined = cstack->cs_flags[cstack->cs_idx]
                                                                & CSF_FUNC_DEF;
 
                // Any variables defined in the previous round are no longer
                // visible.  Keep the first one for ":for", it is the loop
                // variable that we reuse every time around.
-               for (i = cstack->cs_script_var_len[cstack->cs_idx]
+               // Do this backwards, so that vars defined in a later round are
+               // found first.
+               first = cstack->cs_script_var_len[cstack->cs_idx]
                                          + (eap->cmdidx == CMD_while ? 0 : 1);
-                                              i < si->sn_var_vals.ga_len; ++i)
+               for (i = si->sn_var_vals.ga_len - 1; i >= first; --i)
                {
                    svar_T      *sv = ((svar_T *)si->sn_var_vals.ga_data) + i;
 
@@ -1250,6 +1253,12 @@ ex_while(exarg_T *eap)
                        // still exists, from sn_vars.
                        hide_script_var(si, i, func_defined);
                }
+
+               // Start a new block ID, so that variables defined inside the
+               // loop are created new and not shared with the previous loop.
+               // Matters when used in a closure.
+               cstack->cs_block_id[cstack->cs_idx] = ++si->sn_last_block_id;
+               si->sn_current_block_id = si->sn_last_block_id;
            }
        }
        cstack->cs_flags[cstack->cs_idx] =
index f746ca17823181ad02a0ed3ee2521fc791c17ea9..fa9bb0cc206fec56f204a2e2d4e18b2f0c20f993 100644 (file)
@@ -2266,10 +2266,12 @@ def Test_for_loop_with_closure()
         flist[i] = () => inloop
       endfor
       for i in range(5)
-        assert_equal(4, flist[i]())
+        assert_equal(i, flist[i]())
       endfor
   END
-  v9.CheckDefAndScriptSuccess(lines)
+  # FIXME
+  # v9.CheckDefAndScriptSuccess(lines)
+  v9.CheckScriptSuccess(['vim9script'] + lines)
 
   lines =<< trim END
       var flist: list<func>
@@ -2280,10 +2282,12 @@ def Test_for_loop_with_closure()
             }
       endfor
       for i in range(5)
-        assert_equal(4, flist[i]())
+        assert_equal(i, flist[i]())
       endfor
   END
-  v9.CheckDefAndScriptSuccess(lines)
+  # FIXME
+  # v9.CheckDefAndScriptSuccess(lines)
+  v9.CheckScriptSuccess(['vim9script'] + lines)
 enddef
 
 def Test_for_loop_fails()
index 25c28f847bc9ff5596cc269e565af89daf59dc50..dede808bb54903e12f6baef2f4cc894de84f8785 100644 (file)
@@ -703,6 +703,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    459,
 /**/
     458,
 /**/