]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 8.2.4103: Vim9: variable declared in for loop not initialzed v8.2.4103
authorBram Moolenaar <Bram@vim.org>
Sat, 15 Jan 2022 21:44:44 +0000 (21:44 +0000)
committerBram Moolenaar <Bram@vim.org>
Sat, 15 Jan 2022 21:44:44 +0000 (21:44 +0000)
Problem:    Vim9: variable declared in for loop not initialzed.
Solution:   Always initialze the variable. (closes #9535)

src/proto/vim9instr.pro
src/testdir/test_vim9_assign.vim
src/version.c
src/vim9compile.c
src/vim9instr.c

index c9455003e9fc6a90380ac968cc1a00c091882ea2..04ac89c7a83442aef328e8344f0686c963ba8d38 100644 (file)
@@ -63,6 +63,7 @@ int generate_UNPACK(cctx_T *cctx, int var_count, int semicolon);
 int generate_cmdmods(cctx_T *cctx, cmdmod_T *cmod);
 int generate_undo_cmdmods(cctx_T *cctx);
 int generate_store_var(cctx_T *cctx, assign_dest_T dest, int opt_flags, int vimvaridx, int scriptvar_idx, int scriptvar_sid, type_T *type, char_u *name);
+int inside_loop_scope(cctx_T *cctx);
 int generate_store_lhs(cctx_T *cctx, lhs_T *lhs, int instr_count, int is_decl);
 void may_generate_prof_end(cctx_T *cctx, int prof_lnum);
 void delete_instr(isn_T *isn);
index 80ee6b71f60ff86152e07a12cbd3fa70193c1a9e..7f4d87ab3feafde4329b07a5ee91cf2930289705 100644 (file)
@@ -587,6 +587,41 @@ def Test_assign_index()
   CheckDefFailure(lines, 'E1012: Type mismatch; expected list<number> but got dict<unknown>', 2)
 enddef
 
+def Test_init_in_for_loop()
+  var lines =<< trim END
+      var l: list<number> = []
+      for i in [3, 4]
+        var n: number
+        add(l, n)
+        n = 123
+      endfor
+      assert_equal([0, 0], l)
+  END
+  CheckDefAndScriptSuccess(lines)
+
+  lines =<< trim END
+      var l: list<number> = []
+      for i in [3, 4]
+        var n: number = 0
+        add(l, n)
+        n = 123
+      endfor
+      assert_equal([0, 0], l)
+  END
+  CheckDefAndScriptSuccess(lines)
+
+  lines =<< trim END
+      var l: list<number> = []
+      for i in [3, 4]
+        var n: number = 3
+        add(l, n)
+        n = 123
+      endfor
+      assert_equal([3, 3], l)
+  END
+  CheckDefAndScriptSuccess(lines)
+enddef
+
 def Test_extend_list()
   var lines =<< trim END
       var l1: list<number>
index dd97a716ec4ca15e54791ace4ae0c47f618da3c3..d0d9b623bb30c0c3476e8817eddfa548190ab9a1 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    4103,
 /**/
     4102,
 /**/
index afc7885434cf82a554830e749935c03dc239b9f8..89520f93b8b36f9b6515a177c2a174fd37bc00af 100644 (file)
@@ -2256,12 +2256,17 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
                    case VAR_VOID:
                    case VAR_INSTR:
                    case VAR_SPECIAL:  // cannot happen
-                       // This is skipped for local variables, they are
-                       // always initialized to zero.
-                       if (lhs.lhs_dest == dest_local)
+                       // This is skipped for local variables, they are always
+                       // initialized to zero.  But in a "for" or "while" loop
+                       // the value may have been changed.
+                       if (lhs.lhs_dest == dest_local
+                                                  && !inside_loop_scope(cctx))
                            skip_store = TRUE;
                        else
+                       {
+                           instr_count = instr->ga_len;
                            generate_PUSHNR(cctx, 0);
+                       }
                        break;
                }
            }
index 50572978a7949876440c7e9efeac915eaefe3e28..493683acb9515987101f77ebb31ac86f4d4ed940 100644 (file)
@@ -1845,6 +1845,25 @@ generate_store_var(
     return FAIL;
 }
 
+/*
+ * Return TRUE when inside a "for" or "while" loop.
+ */
+    int
+inside_loop_scope(cctx_T *cctx)
+{
+    scope_T    *scope = cctx->ctx_scope;
+
+    for (;;)
+    {
+       if (scope == NULL)
+           break;
+       if (scope->se_type == FOR_SCOPE || scope->se_type == WHILE_SCOPE)
+           return TRUE;
+       scope = scope->se_outer;
+    }
+    return FALSE;
+}
+
     int
 generate_store_lhs(cctx_T *cctx, lhs_T *lhs, int instr_count, int is_decl)
 {
@@ -1869,8 +1888,9 @@ generate_store_lhs(cctx_T *cctx, lhs_T *lhs, int instr_count, int is_decl)
            varnumber_T val = isn->isn_arg.number;
            garray_T    *stack = &cctx->ctx_type_stack;
 
-           if (val == 0 && is_decl)
+           if (val == 0 && is_decl && !inside_loop_scope(cctx))
            {
+               // zero is the default value, no need to do anything
                --instr->ga_len;
            }
            else