summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2020-06-18 18:26:24 +0200
committerBram Moolenaar <Bram@vim.org>2020-06-18 18:26:24 +0200
commit72abcf42d4b28719863c3bdf72b4c05d147a7d83 (patch)
tree3238de02c59e8a648e7061a4d63129822b1dae5a
parent158ea175a99fc23eae1b0a5ee9a81cdd973854a6 (diff)
downloadvim-git-72abcf42d4b28719863c3bdf72b4c05d147a7d83.tar.gz
patch 8.2.1001: Vim9: crash with nested "if" and assignmentv8.2.1001
Problem: Vim9: crash with nested "if" and assignment. Solution: Skip more of the assignment. Do not set ctx_skip when code is reachable.
-rw-r--r--src/testdir/test_vim9_script.vim20
-rw-r--r--src/version.c2
-rw-r--r--src/vim9compile.c87
3 files changed, 71 insertions, 38 deletions
diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim
index 2fa88e836..d4cd60222 100644
--- a/src/testdir/test_vim9_script.vim
+++ b/src/testdir/test_vim9_script.vim
@@ -1162,6 +1162,26 @@ def Test_if_const_expr_fails()
call CheckDefFailure(["if has('aaa') ? true false"], 'E109:')
enddef
+def RunNested(i: number): number
+ let x: number = 0
+ if i % 2
+ if 1
+ " comment
+ else
+ " comment
+ endif
+ x += 1
+ else
+ x += 1000
+ endif
+ return x
+enddef
+
+def Test_nested_if()
+ assert_equal(1, RunNested(1))
+ assert_equal(1000, RunNested(2))
+enddef
+
def Test_execute_cmd()
new
setline(1, 'default')
diff --git a/src/version.c b/src/version.c
index 5f4ff7172..5d69674a8 100644
--- a/src/version.c
+++ b/src/version.c
@@ -755,6 +755,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1001,
+/**/
1000,
/**/
999,
diff --git a/src/vim9compile.c b/src/vim9compile.c
index 7beecd9a3..2bfc4d0fe 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -5067,8 +5067,19 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
if (!heredoc)
{
- if (oplen > 0)
+ if (cctx->ctx_skip == TRUE)
{
+ if (oplen > 0 && var_count == 0)
+ {
+ // skip over the "=" and the expression
+ p = skipwhite(op + oplen);
+ compile_expr0(&p, cctx);
+ }
+ }
+ else if (oplen > 0)
+ {
+ type_T *stacktype;
+
// For "var = expr" evaluate the expression.
if (var_count == 0)
{
@@ -5113,52 +5124,47 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
return FAIL;
}
- if (cctx->ctx_skip != TRUE)
+ stacktype = stack->ga_len == 0 ? &t_void
+ : ((type_T **)stack->ga_data)[stack->ga_len - 1];
+ if (lvar != NULL && (is_decl || !has_type))
{
- type_T *stacktype;
-
- stacktype = stack->ga_len == 0 ? &t_void
- : ((type_T **)stack->ga_data)[stack->ga_len - 1];
- if (lvar != NULL && (is_decl || !has_type))
+ if (new_local && !has_type)
{
- if (new_local && !has_type)
+ if (stacktype->tt_type == VAR_VOID)
{
- if (stacktype->tt_type == VAR_VOID)
- {
- emsg(_(e_cannot_use_void));
- goto theend;
- }
- else
- {
- // An empty list or dict has a &t_void member,
- // for a variable that implies &t_any.
- if (stacktype == &t_list_empty)
- lvar->lv_type = &t_list_any;
- else if (stacktype == &t_dict_empty)
- lvar->lv_type = &t_dict_any;
- else
- lvar->lv_type = stacktype;
- }
+ emsg(_(e_cannot_use_void));
+ goto theend;
}
else
{
- type_T *use_type = lvar->lv_type;
+ // An empty list or dict has a &t_void member,
+ // for a variable that implies &t_any.
+ if (stacktype == &t_list_empty)
+ lvar->lv_type = &t_list_any;
+ else if (stacktype == &t_dict_empty)
+ lvar->lv_type = &t_dict_any;
+ else
+ lvar->lv_type = stacktype;
+ }
+ }
+ else
+ {
+ type_T *use_type = lvar->lv_type;
- if (has_index)
- {
- use_type = use_type->tt_member;
- if (use_type == NULL)
- use_type = &t_void;
- }
- if (need_type(stacktype, use_type, -1, cctx)
- == FAIL)
- goto theend;
+ if (has_index)
+ {
+ use_type = use_type->tt_member;
+ if (use_type == NULL)
+ use_type = &t_void;
}
+ if (need_type(stacktype, use_type, -1, cctx)
+ == FAIL)
+ goto theend;
}
- else if (*p != '=' && need_type(stacktype, member_type, -1,
- cctx) == FAIL)
- goto theend;
}
+ else if (*p != '=' && need_type(stacktype, member_type, -1,
+ cctx) == FAIL)
+ goto theend;
}
else if (cmdidx == CMD_const)
{
@@ -5220,6 +5226,10 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
end = p;
}
+ // no need to parse more when skipping
+ if (cctx->ctx_skip == TRUE)
+ break;
+
if (oplen > 0 && *op != '=')
{
type_T *expected = &t_number;
@@ -5806,7 +5816,8 @@ compile_endif(char_u *arg, cctx_T *cctx)
}
// Fill in the "end" label in jumps at the end of the blocks.
compile_fill_jump_to_end(&ifscope->is_end_label, cctx);
- cctx->ctx_skip = FALSE;
+ // TODO: this should restore the value from before the :if
+ cctx->ctx_skip = MAYBE;
drop_scope(cctx);
return arg;