summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2022-01-15 21:44:44 +0000
committerBram Moolenaar <Bram@vim.org>2022-01-15 21:44:44 +0000
commit38ecd9722664049d636f4fba759b3ebbfd34e97d (patch)
tree9c21a2fbb6312962d1531bc721fa5253eedbd7ca
parent857c8bb1bbe754cf2c5b709703d2eb848c800285 (diff)
downloadvim-git-38ecd9722664049d636f4fba759b3ebbfd34e97d.tar.gz
patch 8.2.4103: Vim9: variable declared in for loop not initialzedv8.2.4103
Problem: Vim9: variable declared in for loop not initialzed. Solution: Always initialze the variable. (closes #9535)
-rw-r--r--src/proto/vim9instr.pro1
-rw-r--r--src/testdir/test_vim9_assign.vim35
-rw-r--r--src/version.c2
-rw-r--r--src/vim9compile.c11
-rw-r--r--src/vim9instr.c22
5 files changed, 67 insertions, 4 deletions
diff --git a/src/proto/vim9instr.pro b/src/proto/vim9instr.pro
index c9455003e..04ac89c7a 100644
--- a/src/proto/vim9instr.pro
+++ b/src/proto/vim9instr.pro
@@ -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);
diff --git a/src/testdir/test_vim9_assign.vim b/src/testdir/test_vim9_assign.vim
index 80ee6b71f..7f4d87ab3 100644
--- a/src/testdir/test_vim9_assign.vim
+++ b/src/testdir/test_vim9_assign.vim
@@ -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>
diff --git a/src/version.c b/src/version.c
index dd97a716e..d0d9b623b 100644
--- a/src/version.c
+++ b/src/version.c
@@ -751,6 +751,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 4103,
+/**/
4102,
/**/
4101,
diff --git a/src/vim9compile.c b/src/vim9compile.c
index afc788543..89520f93b 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -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;
}
}
diff --git a/src/vim9instr.c b/src/vim9instr.c
index 50572978a..493683acb 100644
--- a/src/vim9instr.c
+++ b/src/vim9instr.c
@@ -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