forked from aniani/vim
patch 8.2.1864: Vim9: no error for wrong list type
Problem: Vim9: no error for wrong list type. Solution: Add flag to indicate a constant. (closes #7160)
This commit is contained in:
parent
e3c65ce4e5
commit
334a8b4bde
@ -702,6 +702,9 @@ def Test_assign_list()
|
|||||||
nrl[i] = i
|
nrl[i] = i
|
||||||
endfor
|
endfor
|
||||||
assert_equal([0, 1, 2, 3, 4], nrl)
|
assert_equal([0, 1, 2, 3, 4], nrl)
|
||||||
|
|
||||||
|
CheckDefFailure(["var l: list<number> = ['', true]"], 'E1012: Type mismatch; expected list<number> but got list<any>', 1)
|
||||||
|
CheckDefFailure(["var l: list<list<number>> = [['', true]]"], 'E1012: Type mismatch; expected list<list<number>> but got list<list<any>>', 1)
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
def Test_assign_dict()
|
def Test_assign_dict()
|
||||||
@ -718,6 +721,9 @@ def Test_assign_dict()
|
|||||||
nrd[i] = i
|
nrd[i] = i
|
||||||
endfor
|
endfor
|
||||||
assert_equal({'0': 0, '1': 1, '2': 2}, nrd)
|
assert_equal({'0': 0, '1': 1, '2': 2}, nrd)
|
||||||
|
|
||||||
|
CheckDefFailure(["var d: dict<number> = #{a: '', b: true}"], 'E1012: Type mismatch; expected dict<number> but got dict<any>', 1)
|
||||||
|
CheckDefFailure(["var d: dict<dict<number>> = #{x: #{a: '', b: true}}"], 'E1012: Type mismatch; expected dict<dict<number>> but got dict<dict<any>>', 1)
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
def Test_assign_dict_unknown_type()
|
def Test_assign_dict_unknown_type()
|
||||||
|
@ -750,6 +750,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 */
|
||||||
|
/**/
|
||||||
|
1864,
|
||||||
/**/
|
/**/
|
||||||
1863,
|
1863,
|
||||||
/**/
|
/**/
|
||||||
|
@ -814,11 +814,34 @@ generate_TYPECHECK(
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return TRUE if "actual" could be "expected" and a runtime typecheck is to be
|
||||||
|
* used. Return FALSE if the types will never match.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
use_typecheck(type_T *actual, type_T *expected)
|
||||||
|
{
|
||||||
|
if (actual->tt_type == VAR_ANY
|
||||||
|
|| actual->tt_type == VAR_UNKNOWN
|
||||||
|
|| (actual->tt_type == VAR_FUNC
|
||||||
|
&& (expected->tt_type == VAR_FUNC
|
||||||
|
|| expected->tt_type == VAR_PARTIAL)
|
||||||
|
&& (actual->tt_member == &t_any || actual->tt_argcount < 0)))
|
||||||
|
return TRUE;
|
||||||
|
if ((actual->tt_type == VAR_LIST || actual->tt_type == VAR_DICT)
|
||||||
|
&& actual->tt_type == expected->tt_type)
|
||||||
|
// This takes care of a nested list or dict.
|
||||||
|
return use_typecheck(actual->tt_member, expected->tt_member);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check that
|
* Check that
|
||||||
* - "actual" matches "expected" type or
|
* - "actual" matches "expected" type or
|
||||||
* - "actual" is a type that can be "expected" type: add a runtime check; or
|
* - "actual" is a type that can be "expected" type: add a runtime check; or
|
||||||
* - return FAIL.
|
* - return FAIL.
|
||||||
|
* If "actual_is_const" is TRUE then the type won't change at runtime, do not
|
||||||
|
* generate a TYPECHECK.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
need_type(
|
need_type(
|
||||||
@ -826,7 +849,8 @@ need_type(
|
|||||||
type_T *expected,
|
type_T *expected,
|
||||||
int offset,
|
int offset,
|
||||||
cctx_T *cctx,
|
cctx_T *cctx,
|
||||||
int silent)
|
int silent,
|
||||||
|
int actual_is_const)
|
||||||
{
|
{
|
||||||
if (expected == &t_bool && actual != &t_bool
|
if (expected == &t_bool && actual != &t_bool
|
||||||
&& (actual->tt_flags & TTFLAG_BOOL_OK))
|
&& (actual->tt_flags & TTFLAG_BOOL_OK))
|
||||||
@ -841,19 +865,8 @@ need_type(
|
|||||||
return OK;
|
return OK;
|
||||||
|
|
||||||
// If the actual type can be the expected type add a runtime check.
|
// If the actual type can be the expected type add a runtime check.
|
||||||
// TODO: if it's a constant a runtime check makes no sense.
|
// If it's a constant a runtime check makes no sense.
|
||||||
if (actual->tt_type == VAR_ANY
|
if (!actual_is_const && use_typecheck(actual, expected))
|
||||||
|| actual->tt_type == VAR_UNKNOWN
|
|
||||||
|| (actual->tt_type == VAR_FUNC
|
|
||||||
&& (expected->tt_type == VAR_FUNC
|
|
||||||
|| expected->tt_type == VAR_PARTIAL)
|
|
||||||
&& (actual->tt_member == &t_any || actual->tt_argcount < 0))
|
|
||||||
|| (actual->tt_type == VAR_LIST
|
|
||||||
&& expected->tt_type == VAR_LIST
|
|
||||||
&& actual->tt_member == &t_any)
|
|
||||||
|| (actual->tt_type == VAR_DICT
|
|
||||||
&& expected->tt_type == VAR_DICT
|
|
||||||
&& actual->tt_member == &t_any))
|
|
||||||
{
|
{
|
||||||
generate_TYPECHECK(cctx, expected, offset);
|
generate_TYPECHECK(cctx, expected, offset);
|
||||||
return OK;
|
return OK;
|
||||||
@ -1526,7 +1539,8 @@ generate_CALL(cctx_T *cctx, ufunc_T *ufunc, int pushed_argcount)
|
|||||||
else
|
else
|
||||||
expected = ufunc->uf_va_type->tt_member;
|
expected = ufunc->uf_va_type->tt_member;
|
||||||
actual = ((type_T **)stack->ga_data)[stack->ga_len - argcount + i];
|
actual = ((type_T **)stack->ga_data)[stack->ga_len - argcount + i];
|
||||||
if (need_type(actual, expected, -argcount + i, cctx, TRUE) == FAIL)
|
if (need_type(actual, expected, -argcount + i, cctx,
|
||||||
|
TRUE, FALSE) == FAIL)
|
||||||
{
|
{
|
||||||
arg_type_mismatch(expected, actual, i + 1);
|
arg_type_mismatch(expected, actual, i + 1);
|
||||||
return FAIL;
|
return FAIL;
|
||||||
@ -2061,8 +2075,11 @@ may_get_next_line_error(char_u *whitep, char_u **arg, cctx_T *cctx)
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
typval_T pp_tv[PPSIZE]; // stack of ppconst constants
|
typval_T pp_tv[PPSIZE]; // stack of ppconst constants
|
||||||
int pp_used; // active entries in pp_tv[]
|
int pp_used; // active entries in pp_tv[]
|
||||||
|
int pp_is_const; // all generated code was constants, used for a
|
||||||
|
// list or dict with constant members
|
||||||
} ppconst_T;
|
} ppconst_T;
|
||||||
|
|
||||||
|
static int compile_expr0_ext(char_u **arg, cctx_T *cctx, int *is_const);
|
||||||
static int compile_expr0(char_u **arg, cctx_T *cctx);
|
static int compile_expr0(char_u **arg, cctx_T *cctx);
|
||||||
static int compile_expr1(char_u **arg, cctx_T *cctx, ppconst_T *ppconst);
|
static int compile_expr1(char_u **arg, cctx_T *cctx, ppconst_T *ppconst);
|
||||||
|
|
||||||
@ -2629,13 +2646,16 @@ to_name_const_end(char_u *arg)
|
|||||||
/*
|
/*
|
||||||
* parse a list: [expr, expr]
|
* parse a list: [expr, expr]
|
||||||
* "*arg" points to the '['.
|
* "*arg" points to the '['.
|
||||||
|
* ppconst->pp_is_const is set if all items are a constant.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
compile_list(char_u **arg, cctx_T *cctx)
|
compile_list(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
|
||||||
{
|
{
|
||||||
char_u *p = skipwhite(*arg + 1);
|
char_u *p = skipwhite(*arg + 1);
|
||||||
char_u *whitep = *arg + 1;
|
char_u *whitep = *arg + 1;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
int is_const;
|
||||||
|
int is_all_const = TRUE; // reset when non-const encountered
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
@ -2654,8 +2674,10 @@ compile_list(char_u **arg, cctx_T *cctx)
|
|||||||
++p;
|
++p;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (compile_expr0(&p, cctx) == FAIL)
|
if (compile_expr0_ext(&p, cctx, &is_const) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
|
if (!is_const)
|
||||||
|
is_all_const = FALSE;
|
||||||
++count;
|
++count;
|
||||||
if (*p == ',')
|
if (*p == ',')
|
||||||
{
|
{
|
||||||
@ -2671,8 +2693,8 @@ compile_list(char_u **arg, cctx_T *cctx)
|
|||||||
}
|
}
|
||||||
*arg = p;
|
*arg = p;
|
||||||
|
|
||||||
generate_NEWLIST(cctx, count);
|
ppconst->pp_is_const = is_all_const;
|
||||||
return OK;
|
return generate_NEWLIST(cctx, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2772,9 +2794,10 @@ compile_lambda_call(char_u **arg, cctx_T *cctx)
|
|||||||
/*
|
/*
|
||||||
* parse a dict: {'key': val} or #{key: val}
|
* parse a dict: {'key': val} or #{key: val}
|
||||||
* "*arg" points to the '{'.
|
* "*arg" points to the '{'.
|
||||||
|
* ppconst->pp_is_const is set if all item values are a constant.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
compile_dict(char_u **arg, cctx_T *cctx, int literal)
|
compile_dict(char_u **arg, cctx_T *cctx, int literal, ppconst_T *ppconst)
|
||||||
{
|
{
|
||||||
garray_T *instr = &cctx->ctx_instr;
|
garray_T *instr = &cctx->ctx_instr;
|
||||||
garray_T *stack = &cctx->ctx_type_stack;
|
garray_T *stack = &cctx->ctx_type_stack;
|
||||||
@ -2783,6 +2806,8 @@ compile_dict(char_u **arg, cctx_T *cctx, int literal)
|
|||||||
dictitem_T *item;
|
dictitem_T *item;
|
||||||
char_u *whitep = *arg;
|
char_u *whitep = *arg;
|
||||||
char_u *p;
|
char_u *p;
|
||||||
|
int is_const;
|
||||||
|
int is_all_const = TRUE; // reset when non-const encountered
|
||||||
|
|
||||||
if (d == NULL)
|
if (d == NULL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
@ -2827,7 +2852,8 @@ compile_dict(char_u **arg, cctx_T *cctx, int literal)
|
|||||||
{
|
{
|
||||||
type_T *keytype = ((type_T **)stack->ga_data)
|
type_T *keytype = ((type_T **)stack->ga_data)
|
||||||
[stack->ga_len - 1];
|
[stack->ga_len - 1];
|
||||||
if (need_type(keytype, &t_string, -1, cctx, FALSE) == FAIL)
|
if (need_type(keytype, &t_string, -1, cctx,
|
||||||
|
FALSE, FALSE) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2873,8 +2899,10 @@ compile_dict(char_u **arg, cctx_T *cctx, int literal)
|
|||||||
goto failret;
|
goto failret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (compile_expr0(arg, cctx) == FAIL)
|
if (compile_expr0_ext(arg, cctx, &is_const) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
|
if (!is_const)
|
||||||
|
is_all_const = FALSE;
|
||||||
++count;
|
++count;
|
||||||
|
|
||||||
whitep = *arg;
|
whitep = *arg;
|
||||||
@ -2908,6 +2936,7 @@ compile_dict(char_u **arg, cctx_T *cctx, int literal)
|
|||||||
*arg += STRLEN(*arg);
|
*arg += STRLEN(*arg);
|
||||||
|
|
||||||
dict_unref(d);
|
dict_unref(d);
|
||||||
|
ppconst->pp_is_const = is_all_const;
|
||||||
return generate_NEWDICT(cctx, count);
|
return generate_NEWDICT(cctx, count);
|
||||||
|
|
||||||
failret:
|
failret:
|
||||||
@ -3245,6 +3274,7 @@ compile_subscript(
|
|||||||
|
|
||||||
if (generate_ppconst(cctx, ppconst) == FAIL)
|
if (generate_ppconst(cctx, ppconst) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
|
ppconst->pp_is_const = FALSE;
|
||||||
|
|
||||||
// funcref(arg)
|
// funcref(arg)
|
||||||
type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
|
type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
|
||||||
@ -3261,6 +3291,7 @@ compile_subscript(
|
|||||||
|
|
||||||
if (generate_ppconst(cctx, ppconst) == FAIL)
|
if (generate_ppconst(cctx, ppconst) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
|
ppconst->pp_is_const = FALSE;
|
||||||
|
|
||||||
// something->method()
|
// something->method()
|
||||||
// Apply the '!', '-' and '+' first:
|
// Apply the '!', '-' and '+' first:
|
||||||
@ -3316,6 +3347,7 @@ compile_subscript(
|
|||||||
// TODO: recognize list or dict at runtime
|
// TODO: recognize list or dict at runtime
|
||||||
if (generate_ppconst(cctx, ppconst) == FAIL)
|
if (generate_ppconst(cctx, ppconst) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
|
ppconst->pp_is_const = FALSE;
|
||||||
|
|
||||||
++p;
|
++p;
|
||||||
*arg = skipwhite(p);
|
*arg = skipwhite(p);
|
||||||
@ -3371,12 +3403,14 @@ compile_subscript(
|
|||||||
vtype = VAR_DICT;
|
vtype = VAR_DICT;
|
||||||
if (vtype == VAR_STRING || vtype == VAR_LIST || vtype == VAR_BLOB)
|
if (vtype == VAR_STRING || vtype == VAR_LIST || vtype == VAR_BLOB)
|
||||||
{
|
{
|
||||||
if (need_type(valtype, &t_number, -1, cctx, FALSE) == FAIL)
|
if (need_type(valtype, &t_number, -1, cctx,
|
||||||
|
FALSE, FALSE) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
if (is_slice)
|
if (is_slice)
|
||||||
{
|
{
|
||||||
valtype = ((type_T **)stack->ga_data)[stack->ga_len - 2];
|
valtype = ((type_T **)stack->ga_data)[stack->ga_len - 2];
|
||||||
if (need_type(valtype, &t_number, -2, cctx, FALSE) == FAIL)
|
if (need_type(valtype, &t_number, -2, cctx,
|
||||||
|
FALSE, FALSE) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3392,7 +3426,8 @@ compile_subscript(
|
|||||||
*typep = (*typep)->tt_member;
|
*typep = (*typep)->tt_member;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (need_type(*typep, &t_dict_any, -2, cctx, FALSE) == FAIL)
|
if (need_type(*typep, &t_dict_any, -2, cctx,
|
||||||
|
FALSE, FALSE) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
*typep = &t_any;
|
*typep = &t_any;
|
||||||
}
|
}
|
||||||
@ -3441,8 +3476,10 @@ compile_subscript(
|
|||||||
}
|
}
|
||||||
else if (*p == '.' && p[1] != '.')
|
else if (*p == '.' && p[1] != '.')
|
||||||
{
|
{
|
||||||
|
// dictionary member: dict.name
|
||||||
if (generate_ppconst(cctx, ppconst) == FAIL)
|
if (generate_ppconst(cctx, ppconst) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
|
ppconst->pp_is_const = FALSE;
|
||||||
|
|
||||||
*arg = p + 1;
|
*arg = p + 1;
|
||||||
if (may_get_next_line(*arg, arg, cctx) == FAIL)
|
if (may_get_next_line(*arg, arg, cctx) == FAIL)
|
||||||
@ -3450,7 +3487,6 @@ compile_subscript(
|
|||||||
emsg(_(e_missing_name_after_dot));
|
emsg(_(e_missing_name_after_dot));
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
// dictionary member: dict.name
|
|
||||||
p = *arg;
|
p = *arg;
|
||||||
if (eval_isdictc(*p))
|
if (eval_isdictc(*p))
|
||||||
while (eval_isnamec(*p))
|
while (eval_isnamec(*p))
|
||||||
@ -3480,7 +3516,7 @@ compile_subscript(
|
|||||||
* Compile an expression at "*arg" and add instructions to "cctx->ctx_instr".
|
* Compile an expression at "*arg" and add instructions to "cctx->ctx_instr".
|
||||||
* "arg" is advanced until after the expression, skipping white space.
|
* "arg" is advanced until after the expression, skipping white space.
|
||||||
*
|
*
|
||||||
* If the value is a constant "ppconst->pp_ret" will be set.
|
* If the value is a constant "ppconst->pp_used" will be non-zero.
|
||||||
* Before instructions are generated, any values in "ppconst" will generated.
|
* Before instructions are generated, any values in "ppconst" will generated.
|
||||||
*
|
*
|
||||||
* This is the compiling equivalent of eval1(), eval2(), etc.
|
* This is the compiling equivalent of eval1(), eval2(), etc.
|
||||||
@ -3521,6 +3557,8 @@ compile_expr7(
|
|||||||
typval_T *rettv = &ppconst->pp_tv[ppconst->pp_used];
|
typval_T *rettv = &ppconst->pp_tv[ppconst->pp_used];
|
||||||
int used_before = ppconst->pp_used;
|
int used_before = ppconst->pp_used;
|
||||||
|
|
||||||
|
ppconst->pp_is_const = FALSE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Skip '!', '-' and '+' characters. They are handled later.
|
* Skip '!', '-' and '+' characters. They are handled later.
|
||||||
*/
|
*/
|
||||||
@ -3610,7 +3648,7 @@ compile_expr7(
|
|||||||
/*
|
/*
|
||||||
* List: [expr, expr]
|
* List: [expr, expr]
|
||||||
*/
|
*/
|
||||||
case '[': ret = compile_list(arg, cctx);
|
case '[': ret = compile_list(arg, cctx, ppconst);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3619,7 +3657,7 @@ compile_expr7(
|
|||||||
case '#': if ((*arg)[1] == '{')
|
case '#': if ((*arg)[1] == '{')
|
||||||
{
|
{
|
||||||
++*arg;
|
++*arg;
|
||||||
ret = compile_dict(arg, cctx, TRUE);
|
ret = compile_dict(arg, cctx, TRUE, ppconst);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
ret = NOTDONE;
|
ret = NOTDONE;
|
||||||
@ -3638,7 +3676,7 @@ compile_expr7(
|
|||||||
if (ret != FAIL && *start == '>')
|
if (ret != FAIL && *start == '>')
|
||||||
ret = compile_lambda(arg, cctx);
|
ret = compile_lambda(arg, cctx);
|
||||||
else
|
else
|
||||||
ret = compile_dict(arg, cctx, FALSE);
|
ret = compile_dict(arg, cctx, FALSE, ppconst);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -3807,7 +3845,7 @@ compile_expr7t(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
|
|||||||
actual = ((type_T **)stack->ga_data)[stack->ga_len - 1];
|
actual = ((type_T **)stack->ga_data)[stack->ga_len - 1];
|
||||||
if (check_type(want_type, actual, FALSE, 0) == FAIL)
|
if (check_type(want_type, actual, FALSE, 0) == FAIL)
|
||||||
{
|
{
|
||||||
if (need_type(actual, want_type, -1, cctx, FALSE) == FAIL)
|
if (need_type(actual, want_type, -1, cctx, FALSE, FALSE) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4420,9 +4458,11 @@ compile_expr1(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Toplevel expression.
|
* Toplevel expression.
|
||||||
|
* Sets "is_const" (if not NULL) to indicate the value is a constant.
|
||||||
|
* Returns OK or FAIL.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
compile_expr0(char_u **arg, cctx_T *cctx)
|
compile_expr0_ext(char_u **arg, cctx_T *cctx, int *is_const)
|
||||||
{
|
{
|
||||||
ppconst_T ppconst;
|
ppconst_T ppconst;
|
||||||
|
|
||||||
@ -4432,11 +4472,22 @@ compile_expr0(char_u **arg, cctx_T *cctx)
|
|||||||
clear_ppconst(&ppconst);
|
clear_ppconst(&ppconst);
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
if (is_const != NULL)
|
||||||
|
*is_const = ppconst.pp_used > 0 || ppconst.pp_is_const;
|
||||||
if (generate_ppconst(cctx, &ppconst) == FAIL)
|
if (generate_ppconst(cctx, &ppconst) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Toplevel expression.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
compile_expr0(char_u **arg, cctx_T *cctx)
|
||||||
|
{
|
||||||
|
return compile_expr0_ext(arg, cctx, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* compile "return [expr]"
|
* compile "return [expr]"
|
||||||
*/
|
*/
|
||||||
@ -4466,7 +4517,7 @@ compile_return(char_u *arg, int set_return_type, cctx_T *cctx)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (need_type(stack_type, cctx->ctx_ufunc->uf_ret_type, -1,
|
if (need_type(stack_type, cctx->ctx_ufunc->uf_ret_type, -1,
|
||||||
cctx, FALSE) == FAIL)
|
cctx, FALSE, FALSE) == FAIL)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4834,7 +4885,8 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
|||||||
emsg(_(e_cannot_use_void_value));
|
emsg(_(e_cannot_use_void_value));
|
||||||
goto theend;
|
goto theend;
|
||||||
}
|
}
|
||||||
if (need_type(stacktype, &t_list_any, -1, cctx, FALSE) == FAIL)
|
if (need_type(stacktype, &t_list_any, -1, cctx,
|
||||||
|
FALSE, FALSE) == FAIL)
|
||||||
goto theend;
|
goto theend;
|
||||||
// TODO: check the length of a constant list here
|
// TODO: check the length of a constant list here
|
||||||
generate_CHECKLEN(cctx, semicolon ? var_count - 1 : var_count,
|
generate_CHECKLEN(cctx, semicolon ? var_count - 1 : var_count,
|
||||||
@ -5194,6 +5246,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
|||||||
else if (oplen > 0)
|
else if (oplen > 0)
|
||||||
{
|
{
|
||||||
type_T *stacktype;
|
type_T *stacktype;
|
||||||
|
int is_const = FALSE;
|
||||||
|
|
||||||
// For "var = expr" evaluate the expression.
|
// For "var = expr" evaluate the expression.
|
||||||
if (var_count == 0)
|
if (var_count == 0)
|
||||||
@ -5219,7 +5272,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
|||||||
--cctx->ctx_locals.ga_len;
|
--cctx->ctx_locals.ga_len;
|
||||||
instr_count = instr->ga_len;
|
instr_count = instr->ga_len;
|
||||||
p = skipwhite(op + oplen);
|
p = skipwhite(op + oplen);
|
||||||
r = compile_expr0(&p, cctx);
|
r = compile_expr0_ext(&p, cctx, &is_const);
|
||||||
if (new_local)
|
if (new_local)
|
||||||
++cctx->ctx_locals.ga_len;
|
++cctx->ctx_locals.ga_len;
|
||||||
if (r == FAIL)
|
if (r == FAIL)
|
||||||
@ -5281,13 +5334,13 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
|||||||
// could be indexing "any"
|
// could be indexing "any"
|
||||||
use_type = &t_any;
|
use_type = &t_any;
|
||||||
}
|
}
|
||||||
if (need_type(stacktype, use_type, -1, cctx, FALSE)
|
if (need_type(stacktype, use_type, -1, cctx,
|
||||||
== FAIL)
|
FALSE, is_const) == FAIL)
|
||||||
goto theend;
|
goto theend;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (*p != '=' && need_type(stacktype, member_type, -1,
|
else if (*p != '=' && need_type(stacktype, member_type, -1,
|
||||||
cctx, FALSE) == FAIL)
|
cctx, FALSE, FALSE) == FAIL)
|
||||||
goto theend;
|
goto theend;
|
||||||
}
|
}
|
||||||
else if (cmdidx == CMD_final)
|
else if (cmdidx == CMD_final)
|
||||||
@ -5374,7 +5427,8 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
|||||||
// If variable is float operation with number is OK.
|
// If variable is float operation with number is OK.
|
||||||
!(expected == &t_float && stacktype == &t_number) &&
|
!(expected == &t_float && stacktype == &t_number) &&
|
||||||
#endif
|
#endif
|
||||||
need_type(stacktype, expected, -1, cctx, FALSE) == FAIL)
|
need_type(stacktype, expected, -1, cctx,
|
||||||
|
FALSE, FALSE) == FAIL)
|
||||||
goto theend;
|
goto theend;
|
||||||
|
|
||||||
if (*op == '.')
|
if (*op == '.')
|
||||||
@ -5768,7 +5822,7 @@ bool_on_stack(cctx_T *cctx)
|
|||||||
|
|
||||||
type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
|
type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
|
||||||
if (type != &t_bool && type != &t_number && type != &t_any
|
if (type != &t_bool && type != &t_number && type != &t_any
|
||||||
&& need_type(type, &t_bool, -1, cctx, FALSE) == FAIL)
|
&& need_type(type, &t_bool, -1, cctx, FALSE, FALSE) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
@ -6105,7 +6159,7 @@ compile_for(char_u *arg, cctx_T *cctx)
|
|||||||
// Now that we know the type of "var", check that it is a list, now or at
|
// Now that we know the type of "var", check that it is a list, now or at
|
||||||
// runtime.
|
// runtime.
|
||||||
vartype = ((type_T **)stack->ga_data)[stack->ga_len - 1];
|
vartype = ((type_T **)stack->ga_data)[stack->ga_len - 1];
|
||||||
if (need_type(vartype, &t_list_any, -1, cctx, FALSE) == FAIL)
|
if (need_type(vartype, &t_list_any, -1, cctx, FALSE, FALSE) == FAIL)
|
||||||
{
|
{
|
||||||
drop_scope(cctx);
|
drop_scope(cctx);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user