1
0
forked from aniani/vim

patch 8.2.3996: Vim9: type checking lacks information about declared type

Problem:    Vim9: type checking for list and dict lacks information about
            declared type.
Solution:   Add dv_decl_type and lv_decl_type.  Refactor the type stack to
            store two types in each entry.
This commit is contained in:
Bram Moolenaar
2022-01-04 15:17:03 +00:00
parent 9acf2d8be9
commit 078a46161e
17 changed files with 464 additions and 365 deletions

View File

@@ -57,33 +57,45 @@ generate_instr(cctx_T *cctx, isntype_T isn_type)
isn_T *
generate_instr_drop(cctx_T *cctx, isntype_T isn_type, int drop)
{
garray_T *stack = &cctx->ctx_type_stack;
RETURN_NULL_IF_SKIP(cctx);
stack->ga_len -= drop;
cctx->ctx_type_stack.ga_len -= drop;
return generate_instr(cctx, isn_type);
}
/*
* Generate instruction "isn_type" and put "type" on the type stack.
* Generate instruction "isn_type" and put "type" on the type stack,
* use "decl_type" for the declared type.
*/
isn_T *
generate_instr_type(cctx_T *cctx, isntype_T isn_type, type_T *type)
generate_instr_type2(
cctx_T *cctx,
isntype_T isn_type,
type_T *type,
type_T *decl_type)
{
isn_T *isn;
garray_T *stack = &cctx->ctx_type_stack;
if ((isn = generate_instr(cctx, isn_type)) == NULL)
return NULL;
if (GA_GROW_FAILS(stack, 1))
if (push_type_stack2(cctx, type == NULL ? &t_any : type,
decl_type == NULL ? &t_any : decl_type) == FAIL)
return NULL;
((type_T **)stack->ga_data)[stack->ga_len] = type == NULL ? &t_any : type;
++stack->ga_len;
return isn;
}
/*
* Generate instruction "isn_type" and put "type" on the type stack.
* Uses "any" for the declared type, which works for constants. For declared
* variables use generate_instr_type2().
*/
isn_T *
generate_instr_type(cctx_T *cctx, isntype_T isn_type, type_T *type)
{
return generate_instr_type2(cctx, isn_type, type, &t_any);
}
/*
* Generate an ISN_DEBUG instruction.
*/
@@ -111,12 +123,11 @@ may_generate_2STRING(int offset, int tolerant, cctx_T *cctx)
{
isn_T *isn;
isntype_T isntype = ISN_2STRING;
garray_T *stack = &cctx->ctx_type_stack;
type_T **type;
type_T *type;
RETURN_OK_IF_SKIP(cctx);
type = ((type_T **)stack->ga_data) + stack->ga_len + offset;
switch ((*type)->tt_type)
type = get_type_on_stack(cctx, -1 - offset);
switch (type->tt_type)
{
// nothing to be done
case VAR_STRING: return OK;
@@ -152,11 +163,11 @@ may_generate_2STRING(int offset, int tolerant, cctx_T *cctx)
case VAR_JOB:
case VAR_CHANNEL:
case VAR_INSTR:
to_string_error((*type)->tt_type);
to_string_error(type->tt_type);
return FAIL;
}
*type = &t_string;
set_type_on_stack(cctx, &t_string, -1 - offset);
if ((isn = generate_instr(cctx, isntype)) == NULL)
return FAIL;
isn->isn_arg.tostring.offset = offset;
@@ -193,7 +204,6 @@ generate_add_instr(
type_T *type2,
exprtype_T expr_type)
{
garray_T *stack = &cctx->ctx_type_stack;
isn_T *isn = generate_instr_drop(cctx,
vartype == VAR_NUMBER ? ISN_OPNR
: vartype == VAR_LIST ? ISN_ADDLIST
@@ -225,7 +235,7 @@ generate_add_instr(
if (vartype == VAR_LIST
&& type1->tt_type == VAR_LIST && type2->tt_type == VAR_LIST
&& type1->tt_member != type2->tt_member)
(((type_T **)stack->ga_data)[stack->ga_len - 1]) = &t_list_any;
set_type_on_stack(cctx, &t_list_any, 0);
return isn == NULL ? FAIL : OK;
}
@@ -256,7 +266,6 @@ operator_type(type_T *type1, type_T *type2)
int
generate_two_op(cctx_T *cctx, char_u *op)
{
garray_T *stack = &cctx->ctx_type_stack;
type_T *type1;
type_T *type2;
vartype_T vartype;
@@ -265,8 +274,8 @@ generate_two_op(cctx_T *cctx, char_u *op)
RETURN_OK_IF_SKIP(cctx);
// Get the known type of the two items on the stack.
type1 = ((type_T **)stack->ga_data)[stack->ga_len - 2];
type2 = ((type_T **)stack->ga_data)[stack->ga_len - 1];
type1 = get_type_on_stack(cctx, 1);
type2 = get_type_on_stack(cctx, 0);
vartype = operator_type(type1, type2);
switch (*op)
@@ -323,7 +332,7 @@ generate_two_op(cctx_T *cctx, char_u *op)
&& (type2->tt_type == VAR_NUMBER || type2->tt_type == VAR_FLOAT))
type = &t_float;
#endif
((type_T **)stack->ga_data)[stack->ga_len - 1] = type;
set_type_on_stack(cctx, type, 0);
}
return OK;
@@ -415,8 +424,8 @@ generate_COMPARE(cctx_T *cctx, exprtype_T exprtype, int ic)
// Get the known type of the two items on the stack. If they are matching
// use a type-specific instruction. Otherwise fall back to runtime type
// checking.
type1 = ((type_T **)stack->ga_data)[stack->ga_len - 2]->tt_type;
type2 = ((type_T **)stack->ga_data)[stack->ga_len - 1]->tt_type;
type1 = get_type_on_stack(cctx, 1)->tt_type;
type2 = get_type_on_stack(cctx, 0)->tt_type;
isntype = get_compare_isn(exprtype, type1, type2);
if (isntype == ISN_DROP)
return FAIL;
@@ -430,7 +439,7 @@ generate_COMPARE(cctx_T *cctx, exprtype_T exprtype, int ic)
if (stack->ga_len >= 2)
{
--stack->ga_len;
((type_T **)stack->ga_data)[stack->ga_len - 1] = &t_bool;
set_type_on_stack(cctx, &t_bool, 0);
}
return OK;
@@ -444,7 +453,6 @@ generate_COMPARE(cctx_T *cctx, exprtype_T exprtype, int ic)
generate_2BOOL(cctx_T *cctx, int invert, int offset)
{
isn_T *isn;
garray_T *stack = &cctx->ctx_type_stack;
RETURN_OK_IF_SKIP(cctx);
if ((isn = generate_instr(cctx, ISN_2BOOL)) == NULL)
@@ -453,7 +461,7 @@ generate_2BOOL(cctx_T *cctx, int invert, int offset)
isn->isn_arg.tobool.offset = offset;
// type becomes bool
((type_T **)stack->ga_data)[stack->ga_len + offset] = &t_bool;
set_type_on_stack(cctx, &t_bool, -1 - offset);
return OK;
}
@@ -465,14 +473,13 @@ generate_2BOOL(cctx_T *cctx, int invert, int offset)
generate_COND2BOOL(cctx_T *cctx)
{
isn_T *isn;
garray_T *stack = &cctx->ctx_type_stack;
RETURN_OK_IF_SKIP(cctx);
if ((isn = generate_instr(cctx, ISN_COND2BOOL)) == NULL)
return FAIL;
// type becomes bool
((type_T **)stack->ga_data)[stack->ga_len - 1] = &t_bool;
set_type_on_stack(cctx, &t_bool, 0);
return OK;
}
@@ -485,7 +492,6 @@ generate_TYPECHECK(
int argidx)
{
isn_T *isn;
garray_T *stack = &cctx->ctx_type_stack;
RETURN_OK_IF_SKIP(cctx);
if ((isn = generate_instr(cctx, ISN_CHECKTYPE)) == NULL)
@@ -495,7 +501,7 @@ generate_TYPECHECK(
isn->isn_arg.type.ct_arg_idx = (int8_T)argidx;
// type becomes expected
((type_T **)stack->ga_data)[stack->ga_len + offset] = expected;
set_type_on_stack(cctx, expected, -1 - offset);
return OK;
}
@@ -567,7 +573,6 @@ generate_tv_PUSH(cctx_T *cctx, typval_T *tv)
generate_PUSHNR(cctx_T *cctx, varnumber_T number)
{
isn_T *isn;
garray_T *stack = &cctx->ctx_type_stack;
RETURN_OK_IF_SKIP(cctx);
if ((isn = generate_instr_type(cctx, ISN_PUSHNR, &t_number)) == NULL)
@@ -576,7 +581,7 @@ generate_PUSHNR(cctx_T *cctx, varnumber_T number)
if (number == 0 || number == 1)
// A 0 or 1 number can also be used as a bool.
((type_T **)stack->ga_data)[stack->ga_len - 1] = &t_number_bool;
set_type_on_stack(cctx, &t_number_bool, 0);
return OK;
}
@@ -747,9 +752,7 @@ generate_PUSHFUNC(cctx_T *cctx, char_u *name, type_T *type)
generate_GETITEM(cctx_T *cctx, int index, int with_op)
{
isn_T *isn;
garray_T *stack = &cctx->ctx_type_stack;
type_T *type = ((type_T **)stack->ga_data)[stack->ga_len
- (with_op ? 2 : 1)];
type_T *type = get_type_on_stack(cctx, with_op ? 1 : 0);
type_T *item_type = &t_any;
RETURN_OK_IF_SKIP(cctx);
@@ -767,11 +770,7 @@ generate_GETITEM(cctx_T *cctx, int index, int with_op)
isn->isn_arg.getitem.gi_with_op = with_op;
// add the item type to the type stack
if (GA_GROW_FAILS(stack, 1))
return FAIL;
((type_T **)stack->ga_data)[stack->ga_len] = item_type;
++stack->ga_len;
return OK;
return push_type_stack(cctx, item_type);
}
/*
@@ -895,7 +894,7 @@ generate_LOAD(
isn_T *isn;
RETURN_OK_IF_SKIP(cctx);
if ((isn = generate_instr_type(cctx, isn_type, type)) == NULL)
if ((isn = generate_instr_type2(cctx, isn_type, type, type)) == NULL)
return FAIL;
if (name != NULL)
isn->isn_arg.string = vim_strsave(name);
@@ -918,7 +917,7 @@ generate_LOADOUTER(
isn_T *isn;
RETURN_OK_IF_SKIP(cctx);
if ((isn = generate_instr_type(cctx, ISN_LOADOUTER, type)) == NULL)
if ((isn = generate_instr_type2(cctx, ISN_LOADOUTER, type, type)) == NULL)
return FAIL;
isn->isn_arg.outer.outer_idx = idx;
isn->isn_arg.outer.outer_depth = nesting;
@@ -1050,34 +1049,27 @@ generate_VIM9SCRIPT(
generate_NEWLIST(cctx_T *cctx, int count)
{
isn_T *isn;
garray_T *stack = &cctx->ctx_type_stack;
type_T *member_type;
type_T *decl_member_type;
type_T *type;
type_T *member;
type_T *decl_type;
RETURN_OK_IF_SKIP(cctx);
if ((isn = generate_instr(cctx, ISN_NEWLIST)) == NULL)
return FAIL;
isn->isn_arg.number = count;
// get the member type from all the items on the stack.
if (count == 0)
member = &t_unknown;
else
member = get_member_type_from_stack(
((type_T **)stack->ga_data) + stack->ga_len, count, 1,
cctx->ctx_type_list);
type = get_list_type(member, cctx->ctx_type_list);
// Get the member type and the declared member type from all the items on
// the stack.
member_type = get_member_type_from_stack(count, 1, &decl_member_type, cctx);
type = get_list_type(member_type, cctx->ctx_type_list);
decl_type = get_list_type(decl_member_type, cctx->ctx_type_list);
// drop the value types
stack->ga_len -= count;
cctx->ctx_type_stack.ga_len -= count;
// add the list type to the type stack
if (GA_GROW_FAILS(stack, 1))
return FAIL;
((type_T **)stack->ga_data)[stack->ga_len] = type;
++stack->ga_len;
return OK;
return push_type_stack2(cctx, type, decl_type);
}
/*
@@ -1087,33 +1079,26 @@ generate_NEWLIST(cctx_T *cctx, int count)
generate_NEWDICT(cctx_T *cctx, int count)
{
isn_T *isn;
garray_T *stack = &cctx->ctx_type_stack;
type_T *member_type;
type_T *decl_member_type;
type_T *type;
type_T *member;
type_T *decl_type;
RETURN_OK_IF_SKIP(cctx);
if ((isn = generate_instr(cctx, ISN_NEWDICT)) == NULL)
return FAIL;
isn->isn_arg.number = count;
if (count == 0)
member = &t_void;
else
member = get_member_type_from_stack(
((type_T **)stack->ga_data) + stack->ga_len, count, 2,
cctx->ctx_type_list);
type = get_dict_type(member, cctx->ctx_type_list);
member_type = get_member_type_from_stack(count, 2,
&decl_member_type, cctx);
type = get_dict_type(member_type, cctx->ctx_type_list);
decl_type = get_dict_type(decl_member_type, cctx->ctx_type_list);
// drop the key and value types
stack->ga_len -= 2 * count;
cctx->ctx_type_stack.ga_len -= 2 * count;
// add the dict type to the type stack
if (GA_GROW_FAILS(stack, 1))
return FAIL;
((type_T **)stack->ga_data)[stack->ga_len] = type;
++stack->ga_len;
return OK;
return push_type_stack2(cctx, type, decl_type);
}
/*
@@ -1123,7 +1108,7 @@ generate_NEWDICT(cctx_T *cctx, int count)
generate_FUNCREF(cctx_T *cctx, ufunc_T *ufunc)
{
isn_T *isn;
garray_T *stack = &cctx->ctx_type_stack;
type_T *type;
RETURN_OK_IF_SKIP(cctx);
if ((isn = generate_instr(cctx, ISN_FUNCREF)) == NULL)
@@ -1139,13 +1124,8 @@ generate_FUNCREF(cctx_T *cctx, ufunc_T *ufunc)
if (ufunc->uf_flags & FC_CLOSURE)
cctx->ctx_ufunc->uf_flags |= FC_CLOSURE;
if (GA_GROW_FAILS(stack, 1))
return FAIL;
((type_T **)stack->ga_data)[stack->ga_len] =
ufunc->uf_func_type == NULL ? &t_func_any : ufunc->uf_func_type;
++stack->ga_len;
return OK;
type = ufunc->uf_func_type == NULL ? &t_func_any : ufunc->uf_func_type;
return push_type_stack(cctx, type);
}
/*
@@ -1237,20 +1217,14 @@ generate_JUMP_IF_ARG_SET(cctx_T *cctx, int arg_off)
generate_FOR(cctx_T *cctx, int loop_idx)
{
isn_T *isn;
garray_T *stack = &cctx->ctx_type_stack;
RETURN_OK_IF_SKIP(cctx);
if ((isn = generate_instr(cctx, ISN_FOR)) == NULL)
return FAIL;
isn->isn_arg.forloop.for_idx = loop_idx;
if (GA_GROW_FAILS(stack, 1))
return FAIL;
// type doesn't matter, will be stored next
((type_T **)stack->ga_data)[stack->ga_len] = &t_any;
++stack->ga_len;
return OK;
return push_type_stack(cctx, &t_any);
}
/*
* Generate an ISN_TRYCONT instruction.
@@ -1281,9 +1255,11 @@ generate_BCALL(cctx_T *cctx, int func_idx, int argcount, int method_call)
isn_T *isn;
garray_T *stack = &cctx->ctx_type_stack;
int argoff;
type_T **argtypes = NULL;
type_T *shuffled_argtypes[MAX_FUNC_ARGS];
type_T *maptype = NULL;
type2_T *typep;
type2_T *argtypes = NULL;
type2_T shuffled_argtypes[MAX_FUNC_ARGS];
type2_T *maptype = NULL;
type_T *type;
RETURN_OK_IF_SKIP(cctx);
argoff = check_internal_func(func_idx, argcount);
@@ -1301,22 +1277,30 @@ generate_BCALL(cctx_T *cctx, int func_idx, int argcount, int method_call)
if (argcount > 0)
{
// Check the types of the arguments.
argtypes = ((type_T **)stack->ga_data) + stack->ga_len - argcount;
typep = ((type2_T *)stack->ga_data) + stack->ga_len - argcount;
if (method_call && argoff > 1)
{
int i;
for (i = 0; i < argcount; ++i)
shuffled_argtypes[i] = (i < argoff - 1)
? argtypes[i + 1]
: (i == argoff - 1) ? argtypes[0] : argtypes[i];
? typep[i + 1]
: (i == argoff - 1) ? typep[0] : typep[i];
argtypes = shuffled_argtypes;
}
else
{
int i;
for (i = 0; i < argcount; ++i)
shuffled_argtypes[i] = typep[i];
argtypes = shuffled_argtypes;
}
if (internal_func_check_arg_types(argtypes, func_idx, argcount,
cctx) == FAIL)
return FAIL;
if (internal_func_is_map(func_idx))
maptype = *argtypes;
maptype = argtypes;
}
if ((isn = generate_instr(cctx, ISN_BCALL)) == NULL)
@@ -1326,16 +1310,14 @@ generate_BCALL(cctx_T *cctx, int func_idx, int argcount, int method_call)
// Drop the argument types and push the return type.
stack->ga_len -= argcount;
if (GA_GROW_FAILS(stack, 1))
type = internal_func_ret_type(func_idx, argcount, argtypes);
if (push_type_stack(cctx, type) == FAIL)
return FAIL;
((type_T **)stack->ga_data)[stack->ga_len] =
internal_func_ret_type(func_idx, argcount, argtypes);
++stack->ga_len;
if (maptype != NULL && maptype->tt_member != NULL
&& maptype->tt_member != &t_any)
if (maptype != NULL && maptype[0].type_curr->tt_member != NULL
&& maptype[0].type_curr->tt_member != &t_any)
// Check that map() didn't change the item types.
generate_TYPECHECK(cctx, maptype, -1, 1);
generate_TYPECHECK(cctx, maptype[0].type_curr, -1, 1);
return OK;
}
@@ -1347,14 +1329,13 @@ generate_BCALL(cctx_T *cctx, int func_idx, int argcount, int method_call)
int
generate_LISTAPPEND(cctx_T *cctx)
{
garray_T *stack = &cctx->ctx_type_stack;
type_T *list_type;
type_T *item_type;
type_T *expected;
// Caller already checked that list_type is a list.
list_type = ((type_T **)stack->ga_data)[stack->ga_len - 2];
item_type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
list_type = get_type_on_stack(cctx, 1);
item_type = get_type_on_stack(cctx, 0);
expected = list_type->tt_member;
if (need_type(item_type, expected, -1, 0, cctx, FALSE, FALSE) == FAIL)
return FAIL;
@@ -1362,7 +1343,7 @@ generate_LISTAPPEND(cctx_T *cctx)
if (generate_instr(cctx, ISN_LISTAPPEND) == NULL)
return FAIL;
--stack->ga_len; // drop the argument
--cctx->ctx_type_stack.ga_len; // drop the argument
return OK;
}
@@ -1373,18 +1354,17 @@ generate_LISTAPPEND(cctx_T *cctx)
int
generate_BLOBAPPEND(cctx_T *cctx)
{
garray_T *stack = &cctx->ctx_type_stack;
type_T *item_type;
// Caller already checked that blob_type is a blob.
item_type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
item_type = get_type_on_stack(cctx, 0);
if (need_type(item_type, &t_number, -1, 0, cctx, FALSE, FALSE) == FAIL)
return FAIL;
if (generate_instr(cctx, ISN_BLOBAPPEND) == NULL)
return FAIL;
--stack->ga_len; // drop the argument
--cctx->ctx_type_stack.ga_len; // drop the argument
return OK;
}
@@ -1396,7 +1376,6 @@ generate_BLOBAPPEND(cctx_T *cctx)
generate_CALL(cctx_T *cctx, ufunc_T *ufunc, int pushed_argcount)
{
isn_T *isn;
garray_T *stack = &cctx->ctx_type_stack;
int regular_args = ufunc->uf_args.ga_len;
int argcount = pushed_argcount;
@@ -1424,7 +1403,7 @@ generate_CALL(cctx_T *cctx, ufunc_T *ufunc, int pushed_argcount)
type_T *expected;
type_T *actual;
actual = ((type_T **)stack->ga_data)[stack->ga_len - argcount + i];
actual = get_type_on_stack(cctx, argcount - i - 1);
if (actual == &t_special
&& i >= regular_args - ufunc->uf_def_args.ga_len)
{
@@ -1479,14 +1458,11 @@ generate_CALL(cctx_T *cctx, ufunc_T *ufunc, int pushed_argcount)
isn->isn_arg.ufunc.cuf_argcount = argcount;
}
stack->ga_len -= argcount; // drop the arguments
if (GA_GROW_FAILS(stack, 1))
return FAIL;
// add return value
((type_T **)stack->ga_data)[stack->ga_len] = ufunc->uf_ret_type;
++stack->ga_len;
// drop the argument types
cctx->ctx_type_stack.ga_len -= argcount;
return OK;
// add return type
return push_type_stack(cctx, ufunc->uf_ret_type);
}
/*
@@ -1496,7 +1472,6 @@ generate_CALL(cctx_T *cctx, ufunc_T *ufunc, int pushed_argcount)
generate_UCALL(cctx_T *cctx, char_u *name, int argcount)
{
isn_T *isn;
garray_T *stack = &cctx->ctx_type_stack;
RETURN_OK_IF_SKIP(cctx);
if ((isn = generate_instr(cctx, ISN_UCALL)) == NULL)
@@ -1504,14 +1479,11 @@ generate_UCALL(cctx_T *cctx, char_u *name, int argcount)
isn->isn_arg.ufunc.cuf_name = vim_strsave(name);
isn->isn_arg.ufunc.cuf_argcount = argcount;
stack->ga_len -= argcount; // drop the arguments
if (GA_GROW_FAILS(stack, 1))
return FAIL;
// add return value
((type_T **)stack->ga_data)[stack->ga_len] = &t_any;
++stack->ga_len;
// drop the argument types
cctx->ctx_type_stack.ga_len -= argcount;
return OK;
// add return value
return push_type_stack(cctx, &t_any);
}
/*
@@ -1527,7 +1499,6 @@ generate_PCALL(
int at_top)
{
isn_T *isn;
garray_T *stack = &cctx->ctx_type_stack;
type_T *ret_type;
RETURN_OK_IF_SKIP(cctx);
@@ -1557,8 +1528,7 @@ generate_PCALL(
for (i = 0; i < argcount; ++i)
{
int offset = -argcount + i - (at_top ? 0 : 1);
type_T *actual = ((type_T **)stack->ga_data)[
stack->ga_len + offset];
type_T *actual = get_type_on_stack(cctx, -1 - offset);
type_T *expected;
if (varargs && i >= type->tt_argcount - 1)
@@ -1594,10 +1564,11 @@ generate_PCALL(
isn->isn_arg.pfunc.cpf_top = at_top;
isn->isn_arg.pfunc.cpf_argcount = argcount;
stack->ga_len -= argcount; // drop the arguments
// drop the arguments and the funcref/partial
cctx->ctx_type_stack.ga_len -= argcount + 1;
// drop the funcref/partial, get back the return value
((type_T **)stack->ga_data)[stack->ga_len - 1] = ret_type;
// push the return value
push_type_stack(cctx, ret_type);
// If partial is above the arguments it must be cleared and replaced with
// the return value.
@@ -1614,7 +1585,6 @@ generate_PCALL(
generate_STRINGMEMBER(cctx_T *cctx, char_u *name, size_t len)
{
isn_T *isn;
garray_T *stack = &cctx->ctx_type_stack;
type_T *type;
RETURN_OK_IF_SKIP(cctx);
@@ -1623,7 +1593,7 @@ generate_STRINGMEMBER(cctx_T *cctx, char_u *name, size_t len)
isn->isn_arg.string = vim_strnsave(name, len);
// check for dict type
type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
type = get_type_on_stack(cctx, 0);
if (type->tt_type != VAR_DICT && type != &t_any && type != &t_unknown)
{
char *tofree;
@@ -1636,8 +1606,9 @@ generate_STRINGMEMBER(cctx_T *cctx, char_u *name, size_t len)
// change dict type to dict member type
if (type->tt_type == VAR_DICT)
{
((type_T **)stack->ga_data)[stack->ga_len - 1] =
type->tt_member == &t_unknown ? &t_any : type->tt_member;
type_T *ntype = type->tt_member == &t_unknown
? &t_any : type->tt_member;
set_type_on_stack(cctx, ntype, 0);
}
return OK;
@@ -1734,19 +1705,13 @@ generate_EXEC(cctx_T *cctx, isntype_T isntype, char_u *str)
generate_LEGACY_EVAL(cctx_T *cctx, char_u *line)
{
isn_T *isn;
garray_T *stack = &cctx->ctx_type_stack;
RETURN_OK_IF_SKIP(cctx);
if ((isn = generate_instr(cctx, ISN_LEGACY_EVAL)) == NULL)
return FAIL;
isn->isn_arg.string = vim_strsave(line);
if (GA_GROW_FAILS(stack, 1))
return FAIL;
((type_T **)stack->ga_data)[stack->ga_len] = &t_any;
++stack->ga_len;
return OK;
return push_type_stack(cctx, &t_any);
}
int
@@ -1767,17 +1732,12 @@ generate_EXECCONCAT(cctx_T *cctx, int count)
generate_RANGE(cctx_T *cctx, char_u *range)
{
isn_T *isn;
garray_T *stack = &cctx->ctx_type_stack;
if ((isn = generate_instr(cctx, ISN_RANGE)) == NULL)
return FAIL;
isn->isn_arg.string = range;
if (GA_GROW_FAILS(stack, 1))
return FAIL;
((type_T **)stack->ga_data)[stack->ga_len] = &t_number;
++stack->ga_len;
return OK;
return push_type_stack(cctx, &t_number);
}
int