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:
262
src/vim9instr.c
262
src/vim9instr.c
@@ -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
|
||||
|
Reference in New Issue
Block a user