mirror of
https://github.com/vim/vim.git
synced 2025-09-25 03:54:15 -04:00
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:
111
src/vim9expr.c
111
src/vim9expr.c
@@ -77,7 +77,7 @@ clear_ppconst(ppconst_T *ppconst)
|
||||
int
|
||||
compile_member(int is_slice, int *keeping_dict, cctx_T *cctx)
|
||||
{
|
||||
type_T **typep;
|
||||
type2_T *typep;
|
||||
garray_T *stack = &cctx->ctx_type_stack;
|
||||
vartype_T vartype;
|
||||
type_T *idxtype;
|
||||
@@ -85,12 +85,13 @@ compile_member(int is_slice, int *keeping_dict, cctx_T *cctx)
|
||||
// We can index a list, dict and blob. If we don't know the type
|
||||
// we can use the index value type. If we still don't know use an "ANY"
|
||||
// instruction.
|
||||
typep = ((type_T **)stack->ga_data) + stack->ga_len
|
||||
- (is_slice ? 3 : 2);
|
||||
vartype = (*typep)->tt_type;
|
||||
idxtype = ((type_T **)stack->ga_data)[stack->ga_len - 1];
|
||||
// TODO: what about the decl type?
|
||||
typep = (((type2_T *)stack->ga_data) + stack->ga_len - (is_slice ? 3 : 2));
|
||||
vartype = typep->type_curr->tt_type;
|
||||
idxtype = (((type2_T *)stack->ga_data) + stack->ga_len - 1)->type_curr;
|
||||
// If the index is a string, the variable must be a Dict.
|
||||
if ((*typep == &t_any || *typep == &t_unknown) && idxtype == &t_string)
|
||||
if ((typep->type_curr == &t_any || typep->type_curr == &t_unknown)
|
||||
&& idxtype == &t_string)
|
||||
vartype = VAR_DICT;
|
||||
if (vartype == VAR_STRING || vartype == VAR_LIST || vartype == VAR_BLOB)
|
||||
{
|
||||
@@ -98,7 +99,7 @@ compile_member(int is_slice, int *keeping_dict, cctx_T *cctx)
|
||||
return FAIL;
|
||||
if (is_slice)
|
||||
{
|
||||
idxtype = ((type_T **)stack->ga_data)[stack->ga_len - 2];
|
||||
idxtype = get_type_on_stack(cctx, 1);
|
||||
if (need_type(idxtype, &t_number, -2, 0, cctx,
|
||||
FALSE, FALSE) == FAIL)
|
||||
return FAIL;
|
||||
@@ -112,19 +113,29 @@ compile_member(int is_slice, int *keeping_dict, cctx_T *cctx)
|
||||
emsg(_(e_cannot_slice_dictionary));
|
||||
return FAIL;
|
||||
}
|
||||
if ((*typep)->tt_type == VAR_DICT)
|
||||
if (typep->type_curr->tt_type == VAR_DICT)
|
||||
{
|
||||
*typep = (*typep)->tt_member;
|
||||
if (*typep == &t_unknown)
|
||||
typep->type_curr = typep->type_curr->tt_member;
|
||||
if (typep->type_curr == &t_unknown)
|
||||
// empty dict was used
|
||||
*typep = &t_any;
|
||||
typep->type_curr = &t_any;
|
||||
if (typep->type_decl->tt_type == VAR_DICT)
|
||||
{
|
||||
typep->type_decl = typep->type_decl->tt_member;
|
||||
if (typep->type_decl == &t_unknown)
|
||||
// empty dict was used
|
||||
typep->type_decl = &t_any;
|
||||
}
|
||||
else
|
||||
typep->type_decl = typep->type_curr;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (need_type(*typep, &t_dict_any, -2, 0, cctx,
|
||||
if (need_type(typep->type_curr, &t_dict_any, -2, 0, cctx,
|
||||
FALSE, FALSE) == FAIL)
|
||||
return FAIL;
|
||||
*typep = &t_any;
|
||||
typep->type_curr = &t_any;
|
||||
typep->type_decl = &t_any;
|
||||
}
|
||||
if (may_generate_2STRING(-1, FALSE, cctx) == FAIL)
|
||||
return FAIL;
|
||||
@@ -135,7 +146,8 @@ compile_member(int is_slice, int *keeping_dict, cctx_T *cctx)
|
||||
}
|
||||
else if (vartype == VAR_STRING)
|
||||
{
|
||||
*typep = &t_string;
|
||||
typep->type_curr = &t_string;
|
||||
typep->type_decl = &t_string;
|
||||
if ((is_slice
|
||||
? generate_instr_drop(cctx, ISN_STRSLICE, 2)
|
||||
: generate_instr_drop(cctx, ISN_STRINDEX, 1)) == FAIL)
|
||||
@@ -145,18 +157,21 @@ compile_member(int is_slice, int *keeping_dict, cctx_T *cctx)
|
||||
{
|
||||
if (is_slice)
|
||||
{
|
||||
*typep = &t_blob;
|
||||
typep->type_curr = &t_blob;
|
||||
typep->type_decl = &t_blob;
|
||||
if (generate_instr_drop(cctx, ISN_BLOBSLICE, 2) == FAIL)
|
||||
return FAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
*typep = &t_number;
|
||||
typep->type_curr = &t_number;
|
||||
typep->type_decl = &t_number;
|
||||
if (generate_instr_drop(cctx, ISN_BLOBINDEX, 1) == FAIL)
|
||||
return FAIL;
|
||||
}
|
||||
}
|
||||
else if (vartype == VAR_LIST || *typep == &t_any || *typep == &t_unknown)
|
||||
else if (vartype == VAR_LIST || typep->type_curr == &t_any
|
||||
|| typep->type_curr == &t_unknown)
|
||||
{
|
||||
if (is_slice)
|
||||
{
|
||||
@@ -167,12 +182,21 @@ compile_member(int is_slice, int *keeping_dict, cctx_T *cctx)
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((*typep)->tt_type == VAR_LIST)
|
||||
if (typep->type_curr->tt_type == VAR_LIST)
|
||||
{
|
||||
*typep = (*typep)->tt_member;
|
||||
if (*typep == &t_unknown)
|
||||
typep->type_curr = typep->type_curr->tt_member;
|
||||
if (typep->type_curr == &t_unknown)
|
||||
// empty list was used
|
||||
*typep = &t_any;
|
||||
typep->type_curr = &t_any;
|
||||
if (typep->type_decl->tt_type == VAR_LIST)
|
||||
{
|
||||
typep->type_decl = typep->type_decl->tt_member;
|
||||
if (typep->type_decl == &t_unknown)
|
||||
// empty list was used
|
||||
typep->type_decl = &t_any;
|
||||
}
|
||||
else
|
||||
typep->type_decl = typep->type_curr;
|
||||
}
|
||||
if (generate_instr_drop(cctx,
|
||||
vartype == VAR_LIST ? ISN_LISTINDEX : ISN_ANYINDEX, 1)
|
||||
@@ -709,9 +733,7 @@ compile_call(
|
||||
|
||||
if (STRCMP(name, "add") == 0 && argcount == 2)
|
||||
{
|
||||
garray_T *stack = &cctx->ctx_type_stack;
|
||||
type_T *type = ((type_T **)stack->ga_data)[
|
||||
stack->ga_len - 2];
|
||||
type_T *type = get_type_on_stack(cctx, 1);
|
||||
|
||||
// add() can be compiled to instructions if we know the type
|
||||
if (type->tt_type == VAR_LIST)
|
||||
@@ -758,8 +780,7 @@ compile_call(
|
||||
if (STRNCMP(namebuf, "g:", 2) != 0 && !is_autoload
|
||||
&& compile_load(&p, namebuf + varlen, cctx, FALSE, FALSE) == OK)
|
||||
{
|
||||
garray_T *stack = &cctx->ctx_type_stack;
|
||||
type_T *type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
|
||||
type_T *type = get_type_on_stack(cctx, 0);
|
||||
|
||||
res = generate_PCALL(cctx, argcount, namebuf, type, FALSE);
|
||||
goto theend;
|
||||
@@ -1421,10 +1442,9 @@ skip_expr_cctx(char_u **arg, cctx_T *cctx)
|
||||
int
|
||||
bool_on_stack(cctx_T *cctx)
|
||||
{
|
||||
garray_T *stack = &cctx->ctx_type_stack;
|
||||
type_T *type;
|
||||
|
||||
type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
|
||||
type = get_type_on_stack(cctx, 0);
|
||||
if (type == &t_bool)
|
||||
return OK;
|
||||
|
||||
@@ -1470,10 +1490,9 @@ compile_leader(cctx_T *cctx, int numeric_only, char_u *start, char_u **end)
|
||||
{
|
||||
int negate = *p == '-';
|
||||
isn_T *isn;
|
||||
garray_T *stack = &cctx->ctx_type_stack;
|
||||
type_T *type;
|
||||
|
||||
type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
|
||||
type = get_type_on_stack(cctx, 0);
|
||||
if (type != &t_float && need_type(type, &t_number,
|
||||
-1, 0, cctx, FALSE, FALSE) == FAIL)
|
||||
return FAIL;
|
||||
@@ -1594,7 +1613,6 @@ compile_subscript(
|
||||
// is not a function call.
|
||||
if (**arg == '(')
|
||||
{
|
||||
garray_T *stack = &cctx->ctx_type_stack;
|
||||
type_T *type;
|
||||
int argcount = 0;
|
||||
|
||||
@@ -1603,7 +1621,7 @@ compile_subscript(
|
||||
ppconst->pp_is_const = FALSE;
|
||||
|
||||
// funcref(arg)
|
||||
type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
|
||||
type = get_type_on_stack(cctx, 0);
|
||||
|
||||
*arg = skipwhite(p + 1);
|
||||
if (compile_arguments(arg, cctx, &argcount, FALSE) == FAIL)
|
||||
@@ -1672,12 +1690,13 @@ compile_subscript(
|
||||
// instructions of the expression and move the type of the
|
||||
// expression after the argument types. This is what ISN_PCALL
|
||||
// expects.
|
||||
stack = &cctx->ctx_type_stack;
|
||||
arg_isn_count = cctx->ctx_instr.ga_len - expr_isn_end;
|
||||
if (arg_isn_count > 0)
|
||||
{
|
||||
int expr_isn_count = expr_isn_end - expr_isn_start;
|
||||
isn_T *isn = ALLOC_MULT(isn_T, expr_isn_count);
|
||||
type_T *decl_type;
|
||||
type2_T *typep;
|
||||
|
||||
if (isn == NULL)
|
||||
return FAIL;
|
||||
@@ -1693,15 +1712,19 @@ compile_subscript(
|
||||
isn, sizeof(isn_T) * expr_isn_count);
|
||||
vim_free(isn);
|
||||
|
||||
type = ((type_T **)stack->ga_data)[type_idx_start];
|
||||
mch_memmove(((type_T **)stack->ga_data) + type_idx_start,
|
||||
((type_T **)stack->ga_data) + type_idx_start + 1,
|
||||
sizeof(type_T *)
|
||||
typep = ((type2_T *)stack->ga_data) + type_idx_start;
|
||||
type = typep->type_curr;
|
||||
decl_type = typep->type_decl;
|
||||
mch_memmove(((type2_T *)stack->ga_data) + type_idx_start,
|
||||
((type2_T *)stack->ga_data) + type_idx_start + 1,
|
||||
sizeof(type2_T)
|
||||
* (stack->ga_len - type_idx_start - 1));
|
||||
((type_T **)stack->ga_data)[stack->ga_len - 1] = type;
|
||||
typep = ((type2_T *)stack->ga_data) + stack->ga_len - 1;
|
||||
typep->type_curr = type;
|
||||
typep->type_decl = decl_type;
|
||||
}
|
||||
|
||||
type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
|
||||
type = get_type_on_stack(cctx, 0);
|
||||
if (generate_PCALL(cctx, argcount, p - 2, type, FALSE) == FAIL)
|
||||
return FAIL;
|
||||
}
|
||||
@@ -2152,12 +2175,11 @@ compile_expr7(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
|
||||
|
||||
if (want_type != NULL)
|
||||
{
|
||||
garray_T *stack = &cctx->ctx_type_stack;
|
||||
type_T *actual;
|
||||
where_T where = WHERE_INIT;
|
||||
|
||||
generate_ppconst(cctx, ppconst);
|
||||
actual = ((type_T **)stack->ga_data)[stack->ga_len - 1];
|
||||
actual = get_type_on_stack(cctx, 0);
|
||||
if (check_type_maybe(want_type, actual, FALSE, where) != OK)
|
||||
{
|
||||
if (need_type(actual, want_type, -1, 0, cctx, FALSE, FALSE)
|
||||
@@ -2781,7 +2803,7 @@ compile_expr1(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
|
||||
generate_JUMP(cctx, op_falsy
|
||||
? JUMP_AND_KEEP_IF_TRUE : JUMP_IF_FALSE, 0);
|
||||
if (op_falsy)
|
||||
type1 = ((type_T **)stack->ga_data)[stack->ga_len];
|
||||
type1 = get_type_on_stack(cctx, -1);
|
||||
}
|
||||
|
||||
// evaluate the second expression; any type is accepted
|
||||
@@ -2797,8 +2819,8 @@ compile_expr1(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
|
||||
if (!op_falsy)
|
||||
{
|
||||
// remember the type and drop it
|
||||
type1 = get_type_on_stack(cctx, 0);
|
||||
--stack->ga_len;
|
||||
type1 = ((type_T **)stack->ga_data)[stack->ga_len];
|
||||
|
||||
end_idx = instr->ga_len;
|
||||
generate_JUMP(cctx, JUMP_ALWAYS, 0);
|
||||
@@ -2849,7 +2871,8 @@ compile_expr1(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
|
||||
ppconst->pp_is_const = FALSE;
|
||||
|
||||
// If the types differ, the result has a more generic type.
|
||||
typep = ((type_T **)stack->ga_data) + stack->ga_len - 1;
|
||||
typep = &((((type2_T *)stack->ga_data)
|
||||
+ stack->ga_len - 1)->type_curr);
|
||||
common_type(type1, *typep, typep, cctx->ctx_type_list);
|
||||
|
||||
// jump here from JUMP_ALWAYS or JUMP_AND_KEEP_IF_TRUE
|
||||
|
Reference in New Issue
Block a user