mirror of
https://github.com/vim/vim.git
synced 2025-10-04 05:25:06 -04:00
patch 8.2.1001: Vim9: crash with nested "if" and assignment
Problem: Vim9: crash with nested "if" and assignment. Solution: Skip more of the assignment. Do not set ctx_skip when code is reachable.
This commit is contained in:
@@ -1162,6 +1162,26 @@ def Test_if_const_expr_fails()
|
|||||||
call CheckDefFailure(["if has('aaa') ? true false"], 'E109:')
|
call CheckDefFailure(["if has('aaa') ? true false"], 'E109:')
|
||||||
enddef
|
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()
|
def Test_execute_cmd()
|
||||||
new
|
new
|
||||||
setline(1, 'default')
|
setline(1, 'default')
|
||||||
|
@@ -754,6 +754,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
1001,
|
||||||
/**/
|
/**/
|
||||||
1000,
|
1000,
|
||||||
/**/
|
/**/
|
||||||
|
@@ -5067,8 +5067,19 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
|||||||
|
|
||||||
if (!heredoc)
|
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.
|
// For "var = expr" evaluate the expression.
|
||||||
if (var_count == 0)
|
if (var_count == 0)
|
||||||
{
|
{
|
||||||
@@ -5113,52 +5124,47 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
|||||||
return FAIL;
|
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;
|
if (new_local && !has_type)
|
||||||
|
|
||||||
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 (stacktype->tt_type == VAR_VOID)
|
||||||
{
|
{
|
||||||
if (stacktype->tt_type == VAR_VOID)
|
emsg(_(e_cannot_use_void));
|
||||||
{
|
goto theend;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
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 (has_index)
|
if (stacktype == &t_list_empty)
|
||||||
{
|
lvar->lv_type = &t_list_any;
|
||||||
use_type = use_type->tt_member;
|
else if (stacktype == &t_dict_empty)
|
||||||
if (use_type == NULL)
|
lvar->lv_type = &t_dict_any;
|
||||||
use_type = &t_void;
|
else
|
||||||
}
|
lvar->lv_type = stacktype;
|
||||||
if (need_type(stacktype, use_type, -1, cctx)
|
|
||||||
== FAIL)
|
|
||||||
goto theend;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (*p != '=' && need_type(stacktype, member_type, -1,
|
else
|
||||||
cctx) == FAIL)
|
{
|
||||||
goto theend;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else if (*p != '=' && need_type(stacktype, member_type, -1,
|
||||||
|
cctx) == FAIL)
|
||||||
|
goto theend;
|
||||||
}
|
}
|
||||||
else if (cmdidx == CMD_const)
|
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;
|
end = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// no need to parse more when skipping
|
||||||
|
if (cctx->ctx_skip == TRUE)
|
||||||
|
break;
|
||||||
|
|
||||||
if (oplen > 0 && *op != '=')
|
if (oplen > 0 && *op != '=')
|
||||||
{
|
{
|
||||||
type_T *expected = &t_number;
|
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.
|
// Fill in the "end" label in jumps at the end of the blocks.
|
||||||
compile_fill_jump_to_end(&ifscope->is_end_label, cctx);
|
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);
|
drop_scope(cctx);
|
||||||
return arg;
|
return arg;
|
||||||
|
Reference in New Issue
Block a user