diff options
author | Bram Moolenaar <Bram@vim.org> | 2020-06-18 18:26:24 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2020-06-18 18:26:24 +0200 |
commit | 72abcf42d4b28719863c3bdf72b4c05d147a7d83 (patch) | |
tree | 3238de02c59e8a648e7061a4d63129822b1dae5a | |
parent | 158ea175a99fc23eae1b0a5ee9a81cdd973854a6 (diff) | |
download | vim-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.vim | 20 | ||||
-rw-r--r-- | src/version.c | 2 | ||||
-rw-r--r-- | src/vim9compile.c | 87 |
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; |