changeset 30399:7fc27d7ce3b0 v9.0.0535

patch 9.0.0535: closure gets wrong value in for loop with two loop variables Commit: https://github.com/vim/vim/commit/e8e369a796e110760d033e937b40c84e0c5e8b36 Author: Bram Moolenaar <Bram@vim.org> Date: Wed Sep 21 18:59:14 2022 +0100 patch 9.0.0535: closure gets wrong value in for loop with two loop variables Problem: Closure gets wrong value in for loop with two loop variables. Solution: Correctly compute the number of loop variables to clear.
author Bram Moolenaar <Bram@vim.org>
date Wed, 21 Sep 2022 20:00:05 +0200
parents 97d4f8cca6e9
children 034f0e27f178
files src/evalvars.c src/ex_eval.c src/structs.h src/testdir/test_vim9_script.vim src/version.c
diffstat 5 files changed, 34 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/src/evalvars.c
+++ b/src/evalvars.c
@@ -1315,8 +1315,8 @@ skip_var_list(
 	}
 	return p + 1;
     }
-    else
-	return skip_var_one(arg, include_type);
+ 
+    return skip_var_one(arg, include_type);
 }
 
 /*
--- a/src/ex_eval.c
+++ b/src/ex_eval.c
@@ -1240,8 +1240,14 @@ ex_while(exarg_T *eap)
 		// variable that we reuse every time around.
 		// 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);
+		first = cstack->cs_script_var_len[cstack->cs_idx];
+		if (eap->cmdidx == CMD_for)
+		{
+		    forinfo_T	*fi = cstack->cs_forinfo[cstack->cs_idx];
+
+		    first += fi == NULL || fi->fi_varcount == 0
+							 ? 1 : fi->fi_varcount;
+		}
 		for (i = si->sn_var_vals.ga_len - 1; i >= first; --i)
 		{
 		    svar_T	*sv = ((svar_T *)si->sn_var_vals.ga_data) + i;
--- a/src/structs.h
+++ b/src/structs.h
@@ -1630,7 +1630,7 @@ typedef struct svar_S svar_T;
 typedef struct
 {
     int		fi_semicolon;	// TRUE if ending in '; var]'
-    int		fi_varcount;	// nr of variables in the list
+    int		fi_varcount;	// nr of variables in [] or zero
     int		fi_break_count;	// nr of line breaks encountered
     listwatch_T	fi_lw;		// keep an eye on the item used.
     list_T	*fi_list;	// list being used
--- a/src/testdir/test_vim9_script.vim
+++ b/src/testdir/test_vim9_script.vim
@@ -2323,6 +2323,27 @@ def Test_for_loop_with_closure()
       endfor
   END
   v9.CheckDefAndScriptSuccess(lines)
+
+  # using two loop variables
+  lines =<< trim END
+      var lv_list: list<func>
+      var copy_list: list<func>
+      for [idx, c] in items('word')
+        var lidx = idx
+        var lc = c
+        lv_list[idx] = () => {
+              return idx .. c
+            }
+        copy_list[idx] = () => {
+              return lidx .. lc
+            }
+      endfor
+      for [i, c] in items('word')
+        assert_equal(3 .. 'd', lv_list[i]())
+        assert_equal(i .. c, copy_list[i]())
+      endfor
+  END
+  v9.CheckDefAndScriptSuccess(lines)
 enddef
 
 def Test_define_global_closure_in_loops()
--- a/src/version.c
+++ b/src/version.c
@@ -700,6 +700,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    535,
+/**/
     534,
 /**/
     533,