mirror of
https://github.com/vim/vim.git
synced 2026-05-06 12:26:58 -04:00
patch 9.1.2054: Can't unpack tuple from imported function
Problem: Can't unpack tuple from imported function
(Mao-Yining)
Solution: Support multi-variable assignment from a tuple returned by an
imported function (Yegappan Lakshmanan)
fixes: #19080
closes: #19083
Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
committed by
Christian Brabandt
parent
2a3b608355
commit
eb577f9206
+2
-2
@@ -229,7 +229,7 @@ check_arg_type(
|
||||
type_T *actual,
|
||||
argcontext_T *context)
|
||||
{
|
||||
return need_type(actual, expected, FALSE,
|
||||
return need_type(actual, expected, 0,
|
||||
context->arg_idx - context->arg_count, context->arg_idx + 1,
|
||||
context->arg_cctx, FALSE, FALSE);
|
||||
}
|
||||
@@ -243,7 +243,7 @@ check_arg_type_mod(
|
||||
type_T *actual,
|
||||
argcontext_T *context)
|
||||
{
|
||||
if (need_type(actual, expected, FALSE,
|
||||
if (need_type(actual, expected, 0,
|
||||
context->arg_idx - context->arg_count, context->arg_idx + 1,
|
||||
context->arg_cctx, FALSE, FALSE) == FAIL)
|
||||
return FAIL;
|
||||
|
||||
@@ -6,8 +6,8 @@ int script_var_exists(char_u *name, size_t len, cctx_T *cctx, cstack_T *cstack);
|
||||
int cctx_class_method_idx(cctx_T *cctx, char_u *name, size_t len, class_T **cl_ret);
|
||||
int cctx_class_member_idx(cctx_T *cctx, char_u *name, size_t len, class_T **cl_ret);
|
||||
int check_defined(char_u *p, size_t len, cctx_T *cctx, cstack_T *cstack, int is_arg);
|
||||
int need_type_where(type_T *actual, type_T *expected, int number_ok, int offset, where_T where, cctx_T *cctx, int silent, int actual_is_const);
|
||||
int need_type(type_T *actual, type_T *expected, int number_ok, int offset, int arg_idx, cctx_T *cctx, int silent, int actual_is_const);
|
||||
int need_type_where(type_T *actual, type_T *expected, int typechk_flags, int offset, where_T where, cctx_T *cctx, int silent, int actual_is_const);
|
||||
int need_type(type_T *actual, type_T *expected, int typechk_flags, int offset, int arg_idx, cctx_T *cctx, int silent, int actual_is_const);
|
||||
lvar_T *reserve_local(cctx_T *cctx, char_u *name, size_t len, int assign, type_T *type);
|
||||
int get_script_item_idx(int sid, char_u *name, int check_writable, cctx_T *cctx, cstack_T *cstack);
|
||||
imported_T *find_imported(char_u *name, size_t len, int load);
|
||||
|
||||
@@ -16,7 +16,7 @@ int generate_COMPARE(cctx_T *cctx, exprtype_T exprtype, int ic);
|
||||
int generate_CONCAT(cctx_T *cctx, int count);
|
||||
int generate_2BOOL(cctx_T *cctx, int invert, int offset);
|
||||
int generate_COND2BOOL(cctx_T *cctx);
|
||||
int generate_TYPECHECK(cctx_T *cctx, type_T *expected, int number_ok, int offset, int is_var, int argidx);
|
||||
int generate_TYPECHECK(cctx_T *cctx, type_T *expected, int typechk_flags, int offset, int is_var, int argidx);
|
||||
int generate_SETTYPE(cctx_T *cctx, type_T *expected);
|
||||
int generate_PUSHOBJ(cctx_T *cctx);
|
||||
int generate_tv_PUSH(cctx_T *cctx, typval_T *tv);
|
||||
|
||||
+6
-1
@@ -1532,7 +1532,7 @@ struct type_S {
|
||||
vartype_T tt_type;
|
||||
int8_T tt_argcount; // for func, incl. vararg, -1 for unknown
|
||||
int8_T tt_min_argcount; // number of non-optional arguments
|
||||
char_u tt_flags; // TTFLAG_ values
|
||||
short_u tt_flags; // TTFLAG_ values
|
||||
type_T *tt_member; // for list, dict, func return type
|
||||
class_T *tt_class; // for class and object
|
||||
type_T **tt_args; // func argument types, allocated
|
||||
@@ -1551,10 +1551,15 @@ typedef struct {
|
||||
#define TTFLAG_CONST 0x20 // cannot be changed
|
||||
#define TTFLAG_SUPER 0x40 // object from "super".
|
||||
#define TTFLAG_GENERIC 0x80 // generic type
|
||||
#define TTFLAG_TUPLE_OK 0x100 // tuple can be used for a list
|
||||
|
||||
#define IS_GENERIC_TYPE(type) \
|
||||
((type->tt_flags & TTFLAG_GENERIC) == TTFLAG_GENERIC)
|
||||
|
||||
// Type check flags
|
||||
#define TYPECHK_NUMBER_OK 0x1 // number is accepted for a float
|
||||
#define TYPECHK_TUPLE_OK 0x2 // tuple is accepted for a list
|
||||
|
||||
typedef enum {
|
||||
VIM_ACCESS_PRIVATE, // read/write only inside the class
|
||||
VIM_ACCESS_READ, // read everywhere, write only inside the class
|
||||
|
||||
@@ -2356,4 +2356,103 @@ func Test_tuple2list()
|
||||
call v9.CheckSourceDefAndScriptSuccess(lines)
|
||||
endfunc
|
||||
|
||||
" Test for assigning multiple variables (list assign) using an imported
|
||||
" function returning a tuple.
|
||||
func Test_tuple_multi_assign_from_import()
|
||||
let lines =<< trim END
|
||||
vim9script
|
||||
|
||||
export def Fn(): tuple<string, string>
|
||||
return ('aaa', 'bbb')
|
||||
enddef
|
||||
END
|
||||
call writefile(lines, 'Ximporttuplefunc.vim', 'D')
|
||||
|
||||
let lines =<< trim END
|
||||
vim9script
|
||||
|
||||
import "./Ximporttuplefunc.vim" as Xtuple
|
||||
|
||||
def XtestTupleListAssign()
|
||||
const [x, y] = Xtuple.Fn()
|
||||
assert_equal(['aaa', 'bbb'], [x, y])
|
||||
enddef
|
||||
XtestTupleListAssign()
|
||||
|
||||
# Check the generated code
|
||||
def XtestTupleListAssign2()
|
||||
const [x, y] = Xtuple.Fn()
|
||||
enddef
|
||||
var res = execute('disass XtestTupleListAssign2')
|
||||
assert_match('<SNR>\d*_XtestTupleListAssign2\_s*' ..
|
||||
'const \[x, y\] = Xtuple.Fn()\_s*' ..
|
||||
'0 PUSHFUNC "<80><fd>R\d\+_Fn"\_s*' ..
|
||||
'1 PCALL top (argc 0)\_s*' ..
|
||||
'2 PCALL end\_s*' ..
|
||||
'3 CHECKTYPE list<any>|tuple<any> stack\[-1\]\_s*' ..
|
||||
'4 CHECKLEN 2\_s*' ..
|
||||
'5 ITEM 0\_s*' ..
|
||||
'6 LOCKCONST\_s*' ..
|
||||
'7 STORE $0\_s*' ..
|
||||
'8 ITEM 1\_s*' ..
|
||||
'9 LOCKCONST\_s*' ..
|
||||
'10 STORE $1\_s*' ..
|
||||
'11 DROP\_s*' ..
|
||||
'12 RETURN void',
|
||||
res)
|
||||
END
|
||||
call v9.CheckSourceScriptSuccess(lines)
|
||||
endfunc
|
||||
|
||||
" Test for assigning multiple variables in a for loop using an imported
|
||||
" function returning a tuple.
|
||||
func Test_tuple_multi_assign_in_for_loop_from_import()
|
||||
let lines =<< trim END
|
||||
vim9script
|
||||
|
||||
export def Fn(): tuple<...list<tuple<string, string>>>
|
||||
return (('a', 'b'), ('c', 'd'))
|
||||
enddef
|
||||
END
|
||||
call writefile(lines, 'Ximporttupleinfor.vim', 'D')
|
||||
|
||||
let lines =<< trim END
|
||||
vim9script
|
||||
|
||||
import "./Ximporttupleinfor.vim" as Xtuple
|
||||
|
||||
def XtestTupleInFor()
|
||||
var s = ''
|
||||
for [x, y] in Xtuple.Fn()
|
||||
s ..= x .. y
|
||||
endfor
|
||||
assert_equal('abcd', s)
|
||||
enddef
|
||||
XtestTupleInFor()
|
||||
|
||||
# Check the generated code
|
||||
def XtestTupleInFor2()
|
||||
for [x, y] in Xtuple.Fn()
|
||||
endfor
|
||||
enddef
|
||||
var res = execute('disass XtestTupleInFor2')
|
||||
assert_match('<SNR>\d*_XtestTupleInFor2\_s*' ..
|
||||
'for \[x, y\] in Xtuple.Fn()\_s*' ..
|
||||
'0 STORE -1 in $0\_s*' ..
|
||||
'1 PUSHFUNC "<80><fd>R\d\+_Fn"\_s*' ..
|
||||
'2 PCALL top (argc 0)\_s*' ..
|
||||
'3 PCALL end\_s*' ..
|
||||
'4 FOR $0 -> 9\_s*' ..
|
||||
'5 UNPACK 2\_s*' ..
|
||||
'6 STORE $2\_s*' ..
|
||||
'7 STORE $3\_s*' ..
|
||||
'endfor\_s*' ..
|
||||
'8 JUMP -> 4\_s*' ..
|
||||
'9 DROP\_s*' ..
|
||||
'10 RETURN void',
|
||||
res)
|
||||
END
|
||||
call v9.CheckSourceScriptSuccess(lines)
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
||||
@@ -647,7 +647,7 @@ def Test_disassemble_list_assign()
|
||||
'\d STORE $2\_s*' ..
|
||||
'\[x, y; l\] = g:stringlist\_s*' ..
|
||||
'\d LOADG g:stringlist\_s*' ..
|
||||
'\d CHECKTYPE list<any> stack\[-1\]\_s*' ..
|
||||
'\d CHECKTYPE list<any>|tuple<any> stack\[-1\]\_s*' ..
|
||||
'\d CHECKLEN >= 2\_s*' ..
|
||||
'\d\+ ITEM 0\_s*' ..
|
||||
'\d\+ CHECKTYPE string stack\[-1\] var 1\_s*' ..
|
||||
|
||||
@@ -2064,7 +2064,7 @@ def Test_generic_function_disassemble()
|
||||
'5 STORE $1\_s*' ..
|
||||
'\[x, y\] = g:values\_s*' ..
|
||||
'6 LOADG g:values\_s*\_s*' ..
|
||||
'7 CHECKTYPE list<any> stack\[-1\]\_s*' ..
|
||||
'7 CHECKTYPE list<any>|tuple<any> stack\[-1\]\_s*' ..
|
||||
'8 CHECKLEN 2\_s*' ..
|
||||
'9 ITEM 0\_s*' ..
|
||||
'10 CHECKTYPE list<string> stack\[-1\] var 1\_s*' ..
|
||||
@@ -2201,7 +2201,7 @@ def Test_generic_disassemble_generic_obj_method()
|
||||
'5 STORE $2\_s*' ..
|
||||
'\[x, y\] = g:values\_s*' ..
|
||||
'6 LOADG g:values\_s*' ..
|
||||
'7 CHECKTYPE list<any> stack\[-1\]\_s*' ..
|
||||
'7 CHECKTYPE list<any>|tuple<any> stack\[-1\]\_s*' ..
|
||||
'8 CHECKLEN 2\_s*' ..
|
||||
'9 ITEM 0\_s*' ..
|
||||
'10 CHECKTYPE list<string> stack\[-1\] var 1\_s*' ..
|
||||
@@ -2329,7 +2329,7 @@ def Test_generic_disassemble_generic_class_method()
|
||||
'5 STORE $1\_s*' ..
|
||||
'\[x, y\] = g:values\_s*' ..
|
||||
'6 LOADG g:values\_s*' ..
|
||||
'7 CHECKTYPE list<any> stack\[-1\]\_s*' ..
|
||||
'7 CHECKTYPE list<any>|tuple<any> stack\[-1\]\_s*' ..
|
||||
'8 CHECKLEN 2\_s*' ..
|
||||
'9 ITEM 0\_s*' ..
|
||||
'10 CHECKTYPE list<string> stack\[-1\] var 1\_s*' ..
|
||||
|
||||
@@ -734,6 +734,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
2054,
|
||||
/**/
|
||||
2053,
|
||||
/**/
|
||||
|
||||
+4
-4
@@ -1172,7 +1172,7 @@ compile_for(char_u *arg_start, cctx_T *cctx)
|
||||
if (lhs_type == &t_any)
|
||||
lhs_type = item_type;
|
||||
else if (item_type != &t_unknown
|
||||
&& need_type_where(item_type, lhs_type, FALSE, -1,
|
||||
&& need_type_where(item_type, lhs_type, 0, -1,
|
||||
where, cctx, FALSE, FALSE) == FAIL)
|
||||
goto failed;
|
||||
var_lvar = reserve_local(cctx, arg, varlen, ASSIGN_FINAL,
|
||||
@@ -2625,7 +2625,7 @@ compile_redir(char_u *line, exarg_T *eap, cctx_T *cctx)
|
||||
if (compile_assign_lhs(arg, lhs, CMD_redir,
|
||||
FALSE, FALSE, FALSE, 1, cctx) == FAIL)
|
||||
return NULL;
|
||||
if (need_type(&t_string, lhs->lhs_member_type, FALSE,
|
||||
if (need_type(&t_string, lhs->lhs_member_type, 0,
|
||||
-1, 0, cctx, FALSE, FALSE) == FAIL)
|
||||
return NULL;
|
||||
if (cctx->ctx_skip == SKIP_YES)
|
||||
@@ -2707,7 +2707,7 @@ compile_return(char_u *arg, int check_return_type, int legacy, cctx_T *cctx)
|
||||
int save_flags = cmdmod.cmod_flags;
|
||||
|
||||
generate_LEGACY_EVAL(cctx, p);
|
||||
if (need_type(&t_any, cctx->ctx_ufunc->uf_ret_type, FALSE, -1,
|
||||
if (need_type(&t_any, cctx->ctx_ufunc->uf_ret_type, 0, -1,
|
||||
0, cctx, FALSE, FALSE) == FAIL)
|
||||
return NULL;
|
||||
cmdmod.cmod_flags |= CMOD_LEGACY;
|
||||
@@ -2738,7 +2738,7 @@ compile_return(char_u *arg, int check_return_type, int legacy, cctx_T *cctx)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (need_type(stack_type, cctx->ctx_ufunc->uf_ret_type, FALSE,
|
||||
if (need_type(stack_type, cctx->ctx_ufunc->uf_ret_type, 0,
|
||||
-1, 0, cctx, FALSE, FALSE) == FAIL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+20
-16
@@ -526,12 +526,16 @@ use_typecheck(type_T *actual, type_T *expected)
|
||||
* - return FAIL.
|
||||
* If "actual_is_const" is TRUE then the type won't change at runtime, do not
|
||||
* generate a TYPECHECK.
|
||||
* If "typechk_flags" has TYPECHK_NUMBER_OK, then a number is accepted for
|
||||
* a float.
|
||||
* If "typechk_flags" has TYPECHK_TUPLE_OK, then a tuple is accepted for a
|
||||
* list.
|
||||
*/
|
||||
int
|
||||
need_type_where(
|
||||
type_T *actual,
|
||||
type_T *expected,
|
||||
int number_ok, // expect VAR_FLOAT but VAR_NUMBER is OK
|
||||
int typechk_flags, // acceptable types (type check flags)
|
||||
int offset,
|
||||
where_T where,
|
||||
cctx_T *cctx,
|
||||
@@ -567,7 +571,7 @@ need_type_where(
|
||||
// If the actual type can be the expected type add a runtime check.
|
||||
if (!actual_is_const && ret == MAYBE && use_typecheck(actual, expected))
|
||||
{
|
||||
generate_TYPECHECK(cctx, expected, number_ok, offset,
|
||||
generate_TYPECHECK(cctx, expected, typechk_flags, offset,
|
||||
where.wt_kind == WT_VARIABLE, where.wt_index);
|
||||
return OK;
|
||||
}
|
||||
@@ -581,7 +585,7 @@ need_type_where(
|
||||
need_type(
|
||||
type_T *actual,
|
||||
type_T *expected,
|
||||
int number_ok, // when expected is float number is also OK
|
||||
int typechk_flags, // acceptable types (type check flags)
|
||||
int offset,
|
||||
int arg_idx,
|
||||
cctx_T *cctx,
|
||||
@@ -595,7 +599,7 @@ need_type(
|
||||
where.wt_index = arg_idx;
|
||||
where.wt_kind = WT_ARGUMENT;
|
||||
}
|
||||
return need_type_where(actual, expected, number_ok, offset, where,
|
||||
return need_type_where(actual, expected, typechk_flags, offset, where,
|
||||
cctx, silent, actual_is_const);
|
||||
}
|
||||
|
||||
@@ -2521,7 +2525,7 @@ compile_load_lhs(
|
||||
if (rhs_type != NULL && member_type != NULL
|
||||
&& vartype != VAR_OBJECT && vartype != VAR_CLASS
|
||||
&& rhs_type != &t_void
|
||||
&& need_type(rhs_type, member_type, FALSE,
|
||||
&& need_type(rhs_type, member_type, 0,
|
||||
-3, 0, cctx, FALSE, FALSE) == FAIL)
|
||||
return FAIL;
|
||||
|
||||
@@ -2680,13 +2684,13 @@ compile_assign_unlet(
|
||||
if (range)
|
||||
{
|
||||
type = get_type_on_stack(cctx, 1);
|
||||
if (need_type(type, &t_number, FALSE,
|
||||
if (need_type(type, &t_number, 0,
|
||||
-2, 0, cctx, FALSE, FALSE) == FAIL)
|
||||
return FAIL;
|
||||
}
|
||||
type = get_type_on_stack(cctx, 0);
|
||||
if ((dest_type != VAR_BLOB && type->tt_type != VAR_SPECIAL)
|
||||
&& need_type(type, &t_number, FALSE,
|
||||
&& need_type(type, &t_number, 0,
|
||||
-1, 0, cctx, FALSE, FALSE) == FAIL)
|
||||
return FAIL;
|
||||
}
|
||||
@@ -3041,7 +3045,7 @@ compile_assign_list_check_rhs_type(cctx_T *cctx, cac_T *cac)
|
||||
|
||||
if (need_type(stacktype,
|
||||
stacktype->tt_type == VAR_TUPLE ? &t_tuple_any : &t_list_any,
|
||||
FALSE, -1, 0, cctx, FALSE, FALSE) == FAIL)
|
||||
TYPECHK_TUPLE_OK, -1, 0, cctx, FALSE, FALSE) == FAIL)
|
||||
return FAIL;
|
||||
|
||||
if (stacktype->tt_type == VAR_TUPLE)
|
||||
@@ -3280,7 +3284,7 @@ compile_assign_valid_rhs_type(
|
||||
!has_list_index(cac->cac_var_start + lhs->lhs_varlen, cctx))
|
||||
use_type = lhs->lhs_member_type;
|
||||
|
||||
if (need_type_where(rhs_type, use_type, FALSE, -1, where, cctx, FALSE,
|
||||
if (need_type_where(rhs_type, use_type, 0, -1, where, cctx, FALSE,
|
||||
cac->cac_is_const) == FAIL)
|
||||
return FALSE;
|
||||
|
||||
@@ -3342,7 +3346,7 @@ compile_assign_check_type(cctx_T *cctx, cac_T *cac)
|
||||
|
||||
if (*cac->cac_nextc != '=')
|
||||
{
|
||||
if (need_type(rhs_type, lhs_type, FALSE, -1, 0, cctx, FALSE,
|
||||
if (need_type(rhs_type, lhs_type, 0, -1, 0, cctx, FALSE,
|
||||
FALSE) == FAIL)
|
||||
return FAIL;
|
||||
}
|
||||
@@ -3493,7 +3497,7 @@ compile_assign_compound_op(cctx_T *cctx, cac_T *cac)
|
||||
expected = lhs->lhs_member_type;
|
||||
stacktype = get_type_on_stack(cctx, 0);
|
||||
if (expected != &t_string
|
||||
&& need_type(stacktype, expected, FALSE, -1, 0, cctx,
|
||||
&& need_type(stacktype, expected, 0, -1, 0, cctx,
|
||||
FALSE, FALSE) == FAIL)
|
||||
return FAIL;
|
||||
else if (may_generate_2STRING(-1, TOSTRING_NONE, cctx) == FAIL)
|
||||
@@ -3511,8 +3515,8 @@ compile_assign_compound_op(cctx_T *cctx, cac_T *cac)
|
||||
// If variable is float operation with number is OK.
|
||||
!(expected == &t_float && (stacktype == &t_number
|
||||
|| stacktype == &t_number_bool))
|
||||
&& need_type(stacktype, expected, TRUE, -1, 0, cctx,
|
||||
FALSE, FALSE) == FAIL)
|
||||
&& need_type(stacktype, expected, TYPECHK_NUMBER_OK, -1, 0,
|
||||
cctx, FALSE, FALSE) == FAIL)
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
@@ -3659,7 +3663,7 @@ compile_assign_process_variables(
|
||||
SOURCING_LNUM = cac->cac_start_lnum;
|
||||
if (cac->cac_lhs.lhs_has_type
|
||||
&& need_type(&t_list_string, cac->cac_lhs.lhs_type,
|
||||
FALSE, -1, 0, cctx, FALSE, FALSE) == FAIL)
|
||||
0, -1, 0, cctx, FALSE, FALSE) == FAIL)
|
||||
return FAIL;
|
||||
}
|
||||
else
|
||||
@@ -4119,7 +4123,7 @@ obj_constructor_prologue(ufunc_T *ufunc, cctx_T *cctx)
|
||||
where_T where = WHERE_INIT;
|
||||
where.wt_kind = WT_MEMBER;
|
||||
where.wt_func_name = (char *)m->ocm_name.string;
|
||||
if (need_type_where(type, m->ocm_type, FALSE, -1,
|
||||
if (need_type_where(type, m->ocm_type, 0, -1,
|
||||
where, cctx, FALSE, FALSE) == FAIL)
|
||||
return FAIL;
|
||||
}
|
||||
@@ -4224,7 +4228,7 @@ compile_def_function_default_args(
|
||||
ufunc->uf_arg_types[arg_idx] = val_type;
|
||||
}
|
||||
else if (need_type_where(val_type, ufunc->uf_arg_types[arg_idx],
|
||||
FALSE, -1, where, cctx, FALSE, FALSE) == FAIL)
|
||||
0, -1, where, cctx, FALSE, FALSE) == FAIL)
|
||||
return FAIL;
|
||||
|
||||
if (generate_STORE(cctx, ISN_STORE, i - count - off, NULL) == FAIL)
|
||||
|
||||
@@ -7871,6 +7871,9 @@ list_instructions(char *pfx, isn_T *instr, int instr_count, ufunc_T *ufunc)
|
||||
if (ct->ct_type->tt_type == VAR_FLOAT
|
||||
&& (ct->ct_type->tt_flags & TTFLAG_NUMBER_OK))
|
||||
typename = "float|number";
|
||||
else if (ct->ct_type->tt_type == VAR_LIST
|
||||
&& (ct->ct_type->tt_flags & TTFLAG_TUPLE_OK))
|
||||
typename = "list<any>|tuple<any>";
|
||||
else
|
||||
typename = type_name(ct->ct_type, &tofree);
|
||||
|
||||
|
||||
+9
-9
@@ -162,13 +162,13 @@ compile_member(int is_slice, int *keeping_dict, cctx_T *cctx)
|
||||
if (vartype == VAR_STRING || vartype == VAR_LIST || vartype == VAR_BLOB
|
||||
|| vartype == VAR_TUPLE)
|
||||
{
|
||||
if (need_type(idxtype, &t_number, FALSE,
|
||||
if (need_type(idxtype, &t_number, 0,
|
||||
-1, 0, cctx, FALSE, FALSE) == FAIL)
|
||||
return FAIL;
|
||||
if (is_slice)
|
||||
{
|
||||
idxtype = get_type_on_stack(cctx, 1);
|
||||
if (need_type(idxtype, &t_number, FALSE,
|
||||
if (need_type(idxtype, &t_number, 0,
|
||||
-2, 0, cctx, FALSE, FALSE) == FAIL)
|
||||
return FAIL;
|
||||
}
|
||||
@@ -199,7 +199,7 @@ compile_member(int is_slice, int *keeping_dict, cctx_T *cctx)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (need_type(typep->type_curr, &t_dict_any, FALSE,
|
||||
if (need_type(typep->type_curr, &t_dict_any, 0,
|
||||
-2, 0, cctx, FALSE, FALSE) == FAIL)
|
||||
return FAIL;
|
||||
typep->type_curr = &t_any;
|
||||
@@ -2374,7 +2374,7 @@ bool_on_stack(cctx_T *cctx)
|
||||
// This requires a runtime type check.
|
||||
return generate_COND2BOOL(cctx);
|
||||
|
||||
return need_type(type, &t_bool, FALSE, -1, 0, cctx, FALSE, FALSE);
|
||||
return need_type(type, &t_bool, 0, -1, 0, cctx, FALSE, FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2408,7 +2408,7 @@ compile_leader(cctx_T *cctx, int numeric_only, char_u *start, char_u **end)
|
||||
{
|
||||
type_T *type = get_type_on_stack(cctx, 0);
|
||||
if (type->tt_type != VAR_FLOAT && need_type(type, &t_number,
|
||||
FALSE, -1, 0, cctx, FALSE, FALSE) == FAIL)
|
||||
0, -1, 0, cctx, FALSE, FALSE) == FAIL)
|
||||
return FAIL;
|
||||
|
||||
// only '-' has an effect, for '+' we only check the type
|
||||
@@ -3196,8 +3196,8 @@ compile_expr8(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
|
||||
actual = get_type_on_stack(cctx, 0);
|
||||
if (check_type_maybe(want_type, actual, FALSE, where) != OK)
|
||||
{
|
||||
if (need_type_where(actual, want_type, FALSE, -1, where, cctx, FALSE, FALSE)
|
||||
== FAIL)
|
||||
if (need_type_where(actual, want_type, 0, -1, where, cctx, FALSE,
|
||||
FALSE) == FAIL)
|
||||
return FAIL;
|
||||
}
|
||||
}
|
||||
@@ -3438,7 +3438,7 @@ compile_expr5(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
|
||||
{
|
||||
type_T *t = get_type_on_stack(cctx, 0);
|
||||
|
||||
if (need_type(t, &t_number, FALSE, 0, 0, cctx, FALSE, FALSE) == FAIL)
|
||||
if (need_type(t, &t_number, 0, 0, 0, cctx, FALSE, FALSE) == FAIL)
|
||||
{
|
||||
emsg(_(e_bitshift_ops_must_be_number));
|
||||
return FAIL;
|
||||
@@ -3493,7 +3493,7 @@ compile_expr5(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (need_type(get_type_on_stack(cctx, 0), &t_number, FALSE,
|
||||
if (need_type(get_type_on_stack(cctx, 0), &t_number, 0,
|
||||
0, 0, cctx, FALSE, FALSE) == FAIL)
|
||||
{
|
||||
emsg(_(e_bitshift_ops_must_be_number));
|
||||
|
||||
+14
-9
@@ -694,7 +694,7 @@ generate_COND2BOOL(cctx_T *cctx)
|
||||
generate_TYPECHECK(
|
||||
cctx_T *cctx,
|
||||
type_T *expected,
|
||||
int number_ok, // add TTFLAG_NUMBER_OK flag
|
||||
int typechk_flags, // type check flags
|
||||
int offset,
|
||||
int is_var,
|
||||
int argidx)
|
||||
@@ -705,7 +705,10 @@ generate_TYPECHECK(
|
||||
if ((isn = generate_instr(cctx, ISN_CHECKTYPE)) == NULL)
|
||||
return FAIL;
|
||||
type_T *tt;
|
||||
if (expected->tt_type == VAR_FLOAT && number_ok)
|
||||
if ((expected->tt_type == VAR_FLOAT
|
||||
&& (typechk_flags & TYPECHK_NUMBER_OK))
|
||||
|| (expected->tt_type == VAR_LIST
|
||||
&& (typechk_flags & TYPECHK_TUPLE_OK)))
|
||||
{
|
||||
// always allocate, also for static types
|
||||
tt = ALLOC_ONE(type_T);
|
||||
@@ -713,7 +716,10 @@ generate_TYPECHECK(
|
||||
{
|
||||
*tt = *expected;
|
||||
tt->tt_flags &= ~TTFLAG_STATIC;
|
||||
tt->tt_flags |= TTFLAG_NUMBER_OK;
|
||||
if (typechk_flags & TYPECHK_NUMBER_OK)
|
||||
tt->tt_flags |= TTFLAG_NUMBER_OK;
|
||||
else
|
||||
tt->tt_flags |= TTFLAG_TUPLE_OK;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1846,7 +1852,7 @@ generate_BCALL(cctx_T *cctx, int func_idx, int argcount, int method_call)
|
||||
if (maptype != NULL && maptype[0].type_decl->tt_member != NULL
|
||||
&& maptype[0].type_decl->tt_member != &t_any)
|
||||
// Check that map() didn't change the item types.
|
||||
generate_TYPECHECK(cctx, maptype[0].type_decl, FALSE, -1, FALSE, 1);
|
||||
generate_TYPECHECK(cctx, maptype[0].type_decl, 0, -1, FALSE, 1);
|
||||
|
||||
return OK;
|
||||
}
|
||||
@@ -1870,7 +1876,7 @@ generate_LISTAPPEND(cctx_T *cctx)
|
||||
return FAIL;
|
||||
item_type = get_type_on_stack(cctx, 0);
|
||||
expected = list_type->tt_member;
|
||||
if (need_type(item_type, expected, FALSE, -1, 0, cctx, FALSE, FALSE) == FAIL)
|
||||
if (need_type(item_type, expected, 0, -1, 0, cctx, FALSE, FALSE) == FAIL)
|
||||
return FAIL;
|
||||
|
||||
if (generate_instr(cctx, ISN_LISTAPPEND) == NULL)
|
||||
@@ -1893,8 +1899,7 @@ generate_BLOBAPPEND(cctx_T *cctx)
|
||||
if (arg_type_modifiable(get_decl_type_on_stack(cctx, 1), 1) == FAIL)
|
||||
return FAIL;
|
||||
item_type = get_type_on_stack(cctx, 0);
|
||||
if (need_type(item_type, &t_number, FALSE,
|
||||
-1, 0, cctx, FALSE, FALSE) == FAIL)
|
||||
if (need_type(item_type, &t_number, 0, -1, 0, cctx, FALSE, FALSE) == FAIL)
|
||||
return FAIL;
|
||||
|
||||
if (generate_instr(cctx, ISN_BLOBAPPEND) == NULL)
|
||||
@@ -1971,7 +1976,7 @@ generate_CALL(
|
||||
expected = &t_any;
|
||||
else
|
||||
expected = ufunc->uf_va_type->tt_member;
|
||||
if (need_type(actual, expected, FALSE,
|
||||
if (need_type(actual, expected, 0,
|
||||
-argcount + i, i + 1, cctx, TRUE, FALSE) == FAIL)
|
||||
{
|
||||
arg_type_mismatch(expected, actual, i + 1);
|
||||
@@ -2108,7 +2113,7 @@ check_func_args_from_type(
|
||||
expected = &t_any;
|
||||
else
|
||||
expected = type->tt_args[i];
|
||||
if (need_type(actual, expected, FALSE,
|
||||
if (need_type(actual, expected, 0,
|
||||
offset, i + 1, cctx, TRUE, FALSE) == FAIL)
|
||||
{
|
||||
arg_type_mismatch(expected, actual, i + 1);
|
||||
|
||||
@@ -1372,6 +1372,11 @@ check_type_maybe(
|
||||
|| (actual->tt_flags & TTFLAG_FLOAT_OK)))
|
||||
// Using a number where a float is expected is OK here.
|
||||
return OK;
|
||||
if (expected->tt_type == VAR_LIST
|
||||
&& actual->tt_type == VAR_TUPLE
|
||||
&& (expected->tt_flags & TTFLAG_TUPLE_OK))
|
||||
// Using a tuple where a list is expected is OK here.
|
||||
return OK;
|
||||
if (give_msg)
|
||||
type_mismatch_where(expected, actual, where);
|
||||
return FAIL;
|
||||
|
||||
Reference in New Issue
Block a user