mirror of
https://github.com/vim/vim.git
synced 2025-09-25 03:54:15 -04:00
patch 8.2.1691: Vim9: list<any> is not accepted where list<number> is expected
Problem: Vim9: list<any> is not accepted where list<number> is expected. Solution: Add functions to allocate and free a type_T, use it in ISN_CHECKTYPE. (closes #6959)
This commit is contained in:
@@ -52,7 +52,7 @@ EXTERN char e_type_not_recognized_str[]
|
||||
EXTERN char e_name_too_long_str[]
|
||||
INIT(= N_("E1011: name too long: %s"));
|
||||
EXTERN char e_type_mismatch_expected_str_but_got_str[]
|
||||
INIT(= N_("E1012: type mismatch, expected %s but got %s"));
|
||||
INIT(= N_("E1012: Type mismatch; expected %s but got %s"));
|
||||
EXTERN char e_argument_nr_type_mismatch_expected_str_but_got_str[]
|
||||
INIT(= N_("E1013: argument %d: type mismatch, expected %s but got %s"));
|
||||
EXTERN char e_invalid_key_str[]
|
||||
|
@@ -386,11 +386,14 @@ ret_argv(int argcount, type_T **argtypes UNUSED)
|
||||
static type_T *
|
||||
ret_remove(int argcount UNUSED, type_T **argtypes)
|
||||
{
|
||||
if (argtypes[0]->tt_type == VAR_LIST
|
||||
|| argtypes[0]->tt_type == VAR_DICT)
|
||||
return argtypes[0]->tt_member;
|
||||
if (argtypes[0]->tt_type == VAR_BLOB)
|
||||
return &t_number;
|
||||
if (argtypes != NULL)
|
||||
{
|
||||
if (argtypes[0]->tt_type == VAR_LIST
|
||||
|| argtypes[0]->tt_type == VAR_DICT)
|
||||
return argtypes[0]->tt_member;
|
||||
if (argtypes[0]->tt_type == VAR_BLOB)
|
||||
return &t_number;
|
||||
}
|
||||
return &t_any;
|
||||
}
|
||||
|
||||
@@ -2915,7 +2918,7 @@ ret_f_function(int argcount, type_T **argtypes)
|
||||
{
|
||||
if (argcount == 1 && argtypes[0]->tt_type == VAR_STRING)
|
||||
return &t_func_any;
|
||||
return &t_func_void;
|
||||
return &t_func_unknown;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@@ -391,42 +391,41 @@ EXTERN sctx_T current_sctx INIT4(0, 0, 0, 0);
|
||||
|
||||
|
||||
// Commonly used types.
|
||||
EXTERN type_T t_unknown INIT6(VAR_UNKNOWN, 0, 0, 0, NULL, NULL);
|
||||
EXTERN type_T t_any INIT6(VAR_ANY, 0, 0, 0, NULL, NULL);
|
||||
EXTERN type_T t_void INIT6(VAR_VOID, 0, 0, 0, NULL, NULL);
|
||||
EXTERN type_T t_bool INIT6(VAR_BOOL, 0, 0, 0, NULL, NULL);
|
||||
EXTERN type_T t_special INIT6(VAR_SPECIAL, 0, 0, 0, NULL, NULL);
|
||||
EXTERN type_T t_number INIT6(VAR_NUMBER, 0, 0, 0, NULL, NULL);
|
||||
EXTERN type_T t_float INIT6(VAR_FLOAT, 0, 0, 0, NULL, NULL);
|
||||
EXTERN type_T t_string INIT6(VAR_STRING, 0, 0, 0, NULL, NULL);
|
||||
EXTERN type_T t_blob INIT6(VAR_BLOB, 0, 0, 0, NULL, NULL);
|
||||
EXTERN type_T t_job INIT6(VAR_JOB, 0, 0, 0, NULL, NULL);
|
||||
EXTERN type_T t_channel INIT6(VAR_CHANNEL, 0, 0, 0, NULL, NULL);
|
||||
EXTERN type_T t_unknown INIT6(VAR_UNKNOWN, 0, 0, TTFLAG_STATIC, NULL, NULL);
|
||||
EXTERN type_T t_any INIT6(VAR_ANY, 0, 0, TTFLAG_STATIC, NULL, NULL);
|
||||
EXTERN type_T t_void INIT6(VAR_VOID, 0, 0, TTFLAG_STATIC, NULL, NULL);
|
||||
EXTERN type_T t_bool INIT6(VAR_BOOL, 0, 0, TTFLAG_STATIC, NULL, NULL);
|
||||
EXTERN type_T t_special INIT6(VAR_SPECIAL, 0, 0, TTFLAG_STATIC, NULL, NULL);
|
||||
EXTERN type_T t_number INIT6(VAR_NUMBER, 0, 0, TTFLAG_STATIC, NULL, NULL);
|
||||
EXTERN type_T t_float INIT6(VAR_FLOAT, 0, 0, TTFLAG_STATIC, NULL, NULL);
|
||||
EXTERN type_T t_string INIT6(VAR_STRING, 0, 0, TTFLAG_STATIC, NULL, NULL);
|
||||
EXTERN type_T t_blob INIT6(VAR_BLOB, 0, 0, TTFLAG_STATIC, NULL, NULL);
|
||||
EXTERN type_T t_job INIT6(VAR_JOB, 0, 0, TTFLAG_STATIC, NULL, NULL);
|
||||
EXTERN type_T t_channel INIT6(VAR_CHANNEL, 0, 0, TTFLAG_STATIC, NULL, NULL);
|
||||
|
||||
EXTERN type_T t_func_unknown INIT6(VAR_FUNC, -1, 0, 0, &t_unknown, NULL);
|
||||
EXTERN type_T t_func_void INIT6(VAR_FUNC, -1, 0, 0, &t_void, NULL);
|
||||
EXTERN type_T t_func_any INIT6(VAR_FUNC, -1, 0, 0, &t_any, NULL);
|
||||
EXTERN type_T t_func_number INIT6(VAR_FUNC, -1, 0, 0, &t_number, NULL);
|
||||
EXTERN type_T t_func_string INIT6(VAR_FUNC, -1, 0, 0, &t_string, NULL);
|
||||
EXTERN type_T t_func_0_void INIT6(VAR_FUNC, 0, 0, 0, &t_void, NULL);
|
||||
EXTERN type_T t_func_0_any INIT6(VAR_FUNC, 0, 0, 0, &t_any, NULL);
|
||||
EXTERN type_T t_func_0_number INIT6(VAR_FUNC, 0, 0, 0, &t_number, NULL);
|
||||
EXTERN type_T t_func_0_string INIT6(VAR_FUNC, 0, 0, 0, &t_string, NULL);
|
||||
EXTERN type_T t_func_unknown INIT6(VAR_FUNC, -1, 0, TTFLAG_STATIC, &t_unknown, NULL);
|
||||
EXTERN type_T t_func_void INIT6(VAR_FUNC, -1, 0, TTFLAG_STATIC, &t_void, NULL);
|
||||
EXTERN type_T t_func_any INIT6(VAR_FUNC, -1, 0, TTFLAG_STATIC, &t_any, NULL);
|
||||
EXTERN type_T t_func_number INIT6(VAR_FUNC, -1, 0, TTFLAG_STATIC, &t_number, NULL);
|
||||
EXTERN type_T t_func_string INIT6(VAR_FUNC, -1, 0, TTFLAG_STATIC, &t_string, NULL);
|
||||
EXTERN type_T t_func_0_void INIT6(VAR_FUNC, 0, 0, TTFLAG_STATIC, &t_void, NULL);
|
||||
EXTERN type_T t_func_0_any INIT6(VAR_FUNC, 0, 0, TTFLAG_STATIC, &t_any, NULL);
|
||||
EXTERN type_T t_func_0_number INIT6(VAR_FUNC, 0, 0, TTFLAG_STATIC, &t_number, NULL);
|
||||
EXTERN type_T t_func_0_string INIT6(VAR_FUNC, 0, 0, TTFLAG_STATIC, &t_string, NULL);
|
||||
|
||||
EXTERN type_T t_list_any INIT6(VAR_LIST, 0, 0, 0, &t_any, NULL);
|
||||
EXTERN type_T t_dict_any INIT6(VAR_DICT, 0, 0, 0, &t_any, NULL);
|
||||
EXTERN type_T t_list_empty INIT6(VAR_LIST, 0, 0, 0, &t_unknown, NULL);
|
||||
EXTERN type_T t_dict_empty INIT6(VAR_DICT, 0, 0, 0, &t_unknown, NULL);
|
||||
EXTERN type_T t_list_any INIT6(VAR_LIST, 0, 0, TTFLAG_STATIC, &t_any, NULL);
|
||||
EXTERN type_T t_dict_any INIT6(VAR_DICT, 0, 0, TTFLAG_STATIC, &t_any, NULL);
|
||||
EXTERN type_T t_list_empty INIT6(VAR_LIST, 0, 0, TTFLAG_STATIC, &t_unknown, NULL);
|
||||
EXTERN type_T t_dict_empty INIT6(VAR_DICT, 0, 0, TTFLAG_STATIC, &t_unknown, NULL);
|
||||
|
||||
EXTERN type_T t_list_bool INIT6(VAR_LIST, 0, 0, 0, &t_bool, NULL);
|
||||
EXTERN type_T t_list_number INIT6(VAR_LIST, 0, 0, 0, &t_number, NULL);
|
||||
EXTERN type_T t_list_string INIT6(VAR_LIST, 0, 0, 0, &t_string, NULL);
|
||||
EXTERN type_T t_list_dict_any INIT6(VAR_LIST, 0, 0, 0, &t_dict_any, NULL);
|
||||
|
||||
EXTERN type_T t_dict_bool INIT6(VAR_DICT, 0, 0, 0, &t_bool, NULL);
|
||||
EXTERN type_T t_dict_number INIT6(VAR_DICT, 0, 0, 0, &t_number, NULL);
|
||||
EXTERN type_T t_dict_string INIT6(VAR_DICT, 0, 0, 0, &t_string, NULL);
|
||||
EXTERN type_T t_list_bool INIT6(VAR_LIST, 0, 0, TTFLAG_STATIC, &t_bool, NULL);
|
||||
EXTERN type_T t_list_number INIT6(VAR_LIST, 0, 0, TTFLAG_STATIC, &t_number, NULL);
|
||||
EXTERN type_T t_list_string INIT6(VAR_LIST, 0, 0, TTFLAG_STATIC, &t_string, NULL);
|
||||
EXTERN type_T t_list_dict_any INIT6(VAR_LIST, 0, 0, TTFLAG_STATIC, &t_dict_any, NULL);
|
||||
|
||||
EXTERN type_T t_dict_bool INIT6(VAR_DICT, 0, 0, TTFLAG_STATIC, &t_bool, NULL);
|
||||
EXTERN type_T t_dict_number INIT6(VAR_DICT, 0, 0, TTFLAG_STATIC, &t_number, NULL);
|
||||
EXTERN type_T t_dict_string INIT6(VAR_DICT, 0, 0, TTFLAG_STATIC, &t_string, NULL);
|
||||
|
||||
#endif
|
||||
|
||||
|
@@ -1,6 +1,8 @@
|
||||
/* vim9type.c */
|
||||
type_T *alloc_type(garray_T *type_gap);
|
||||
type_T *get_type_ptr(garray_T *type_gap);
|
||||
void clear_type_list(garray_T *gap);
|
||||
type_T *alloc_type(type_T *type);
|
||||
void free_type(type_T *type);
|
||||
type_T *get_list_type(type_T *member_type, garray_T *type_gap);
|
||||
type_T *get_dict_type(type_T *member_type, garray_T *type_gap);
|
||||
type_T *alloc_func_type(type_T *ret_type, int argcount, garray_T *type_gap);
|
||||
|
@@ -258,7 +258,7 @@ def Test_disassemble_list_assign()
|
||||
'\d STORE $2\_s*' ..
|
||||
'\[x, y; l\] = g:stringlist\_s*' ..
|
||||
'\d LOADG g:stringlist\_s*' ..
|
||||
'\d CHECKTYPE list stack\[-1\]\_s*' ..
|
||||
'\d CHECKTYPE list<any> stack\[-1\]\_s*' ..
|
||||
'\d CHECKLEN >= 2\_s*' ..
|
||||
'\d\+ ITEM 0\_s*' ..
|
||||
'\d\+ CHECKTYPE string stack\[-1\]\_s*' ..
|
||||
@@ -829,7 +829,7 @@ def Test_disassemble_for_loop_eval()
|
||||
'\d STORE -1 in $1\_s*' ..
|
||||
'\d PUSHS "\["one", "two"\]"\_s*' ..
|
||||
'\d BCALL eval(argc 1)\_s*' ..
|
||||
'\d CHECKTYPE list stack\[-1\]\_s*' ..
|
||||
'\d CHECKTYPE list<any> stack\[-1\]\_s*' ..
|
||||
'\d FOR $1 -> \d\+\_s*' ..
|
||||
'\d STORE $2\_s*' ..
|
||||
'res ..= str\_s*' ..
|
||||
@@ -1144,7 +1144,7 @@ def Test_disassemble_any_slice()
|
||||
'\d STORE $0\_s*' ..
|
||||
'return res\_s*' ..
|
||||
'\d LOAD $0\_s*' ..
|
||||
'\d CHECKTYPE list stack\[-1\]\_s*' ..
|
||||
'\d CHECKTYPE list<number> stack\[-1\]\_s*' ..
|
||||
'\d RETURN',
|
||||
instr)
|
||||
assert_equal([2, 3, 4], AnySlice())
|
||||
|
@@ -1438,8 +1438,11 @@ def Test_expr7_vimvar()
|
||||
let old: list<string> = v:oldfiles
|
||||
let compl: dict<any> = v:completed_item
|
||||
|
||||
CheckDefFailure(["let old: list<number> = v:oldfiles"], 'E1012: type mismatch, expected list<number> but got list<string>', 1)
|
||||
CheckDefFailure(["let old: dict<number> = v:completed_item"], 'E1012: type mismatch, expected dict<number> but got dict<any>', 1)
|
||||
CheckDefFailure(["let old: list<number> = v:oldfiles"], 'E1012: Type mismatch; expected list<number> but got list<string>', 1)
|
||||
new
|
||||
exec "normal! afoo fo\<C-N>\<Esc>"
|
||||
CheckDefExecFailure(["let old: dict<number> = v:completed_item"], 'E1012: Type mismatch; expected dict<number> but got dict<string>', 1)
|
||||
bwipe!
|
||||
enddef
|
||||
|
||||
def Test_expr7_special()
|
||||
@@ -1520,14 +1523,14 @@ def Test_expr7_list()
|
||||
|
||||
CheckDefExecFailure(["echo 1", "let x = [][0]", "echo 3"], 'E684:', 2)
|
||||
|
||||
CheckDefExecFailure(["let x = g:list_mixed['xx']"], 'E1029:', 1)
|
||||
CheckDefExecFailure(["let x = g:list_mixed['xx']"], 'E1012:', 1)
|
||||
CheckDefFailure(["let x = g:list_mixed["], 'E1097:', 2)
|
||||
CheckDefFailure(["let x = g:list_mixed[0"], 'E1097:', 2)
|
||||
CheckDefExecFailure(["let x = g:list_empty[3]"], 'E684:', 1)
|
||||
CheckDefFailure(["let l: list<number> = [234, 'x']"], 'E1012:', 1)
|
||||
CheckDefFailure(["let l: list<number> = ['x', 234]"], 'E1012:', 1)
|
||||
CheckDefFailure(["let l: list<string> = [234, 'x']"], 'E1012:', 1)
|
||||
CheckDefFailure(["let l: list<string> = ['x', 123]"], 'E1012:', 1)
|
||||
CheckDefExecFailure(["let l: list<number> = [234, 'x']"], 'E1012:', 1)
|
||||
CheckDefExecFailure(["let l: list<number> = ['x', 234]"], 'E1012:', 1)
|
||||
CheckDefExecFailure(["let l: list<string> = [234, 'x']"], 'E1012:', 1)
|
||||
CheckDefExecFailure(["let l: list<string> = ['x', 123]"], 'E1012:', 1)
|
||||
enddef
|
||||
|
||||
def Test_expr7_list_vim9script()
|
||||
@@ -1731,10 +1734,10 @@ def Test_expr7_dict()
|
||||
CheckDefExecFailure(["let x = g:anint.member"], 'E715:', 1)
|
||||
CheckDefExecFailure(["let x = g:dict_empty.member"], 'E716:', 1)
|
||||
|
||||
CheckDefFailure(['let x: dict<number> = #{a: 234, b: "1"}'], 'E1012:', 1)
|
||||
CheckDefFailure(['let x: dict<number> = #{a: "x", b: 134}'], 'E1012:', 1)
|
||||
CheckDefFailure(['let x: dict<string> = #{a: 234, b: "1"}'], 'E1012:', 1)
|
||||
CheckDefFailure(['let x: dict<string> = #{a: "x", b: 134}'], 'E1012:', 1)
|
||||
CheckDefExecFailure(['let x: dict<number> = #{a: 234, b: "1"}'], 'E1012:', 1)
|
||||
CheckDefExecFailure(['let x: dict<number> = #{a: "x", b: 134}'], 'E1012:', 1)
|
||||
CheckDefExecFailure(['let x: dict<string> = #{a: 234, b: "1"}'], 'E1012:', 1)
|
||||
CheckDefExecFailure(['let x: dict<string> = #{a: "x", b: 134}'], 'E1012:', 1)
|
||||
enddef
|
||||
|
||||
def Test_expr7_dict_vim9script()
|
||||
@@ -1840,7 +1843,7 @@ def Test_expr_member()
|
||||
|
||||
CheckDefFailure(["let x = g:dict_one.#$!"], 'E1002:', 1)
|
||||
CheckDefExecFailure(["let d: dict<any>", "echo d['a']"], 'E716:', 2)
|
||||
CheckDefExecFailure(["let d: dict<number>", "d = g:list_empty"], 'E1029: Expected dict but got list', 2)
|
||||
CheckDefExecFailure(["let d: dict<number>", "d = g:list_empty"], 'E1012: Type mismatch; expected dict<number> but got list<unknown>', 2)
|
||||
enddef
|
||||
|
||||
def Test_expr7_any_index_slice()
|
||||
@@ -2311,7 +2314,7 @@ def Test_expr7_list_subscript()
|
||||
CheckScriptSuccess(['vim9script'] + lines)
|
||||
|
||||
lines = ['let l = [0, 1, 2]', 'echo l[g:astring : g:theone]']
|
||||
CheckDefExecFailure(lines, 'E1029:')
|
||||
CheckDefExecFailure(lines, 'E1012:')
|
||||
CheckScriptFailure(['vim9script'] + lines, 'E1030:', 3)
|
||||
enddef
|
||||
|
||||
|
@@ -30,7 +30,7 @@ enddef
|
||||
def Test_return_something()
|
||||
ReturnString()->assert_equal('string')
|
||||
ReturnNumber()->assert_equal(123)
|
||||
assert_fails('ReturnGlobal()', 'E1029: Expected number but got string', '', 1, 'ReturnGlobal')
|
||||
assert_fails('ReturnGlobal()', 'E1012: Type mismatch; expected number but got string', '', 1, 'ReturnGlobal')
|
||||
enddef
|
||||
|
||||
def Test_missing_return()
|
||||
@@ -487,7 +487,7 @@ def Test_call_funcref()
|
||||
enddef
|
||||
let Funcref: func(string) = function('UseNumber')
|
||||
END
|
||||
CheckScriptFailure(lines, 'E1012: type mismatch, expected func(string) but got func(number)')
|
||||
CheckScriptFailure(lines, 'E1012: Type mismatch; expected func(string) but got func(number)')
|
||||
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
@@ -976,37 +976,37 @@ def Test_func_type_part()
|
||||
let RefVoid: func: void
|
||||
RefVoid = FuncNoArgNoRet
|
||||
RefVoid = FuncOneArgNoRet
|
||||
CheckDefFailure(['let RefVoid: func: void', 'RefVoid = FuncNoArgRetNumber'], 'E1012: type mismatch, expected func() but got func(): number')
|
||||
CheckDefFailure(['let RefVoid: func: void', 'RefVoid = FuncNoArgRetString'], 'E1012: type mismatch, expected func() but got func(): string')
|
||||
CheckDefFailure(['let RefVoid: func: void', 'RefVoid = FuncNoArgRetNumber'], 'E1012: Type mismatch; expected func(...) but got func(): number')
|
||||
CheckDefFailure(['let RefVoid: func: void', 'RefVoid = FuncNoArgRetString'], 'E1012: Type mismatch; expected func(...) but got func(): string')
|
||||
|
||||
let RefAny: func(): any
|
||||
RefAny = FuncNoArgRetNumber
|
||||
RefAny = FuncNoArgRetString
|
||||
CheckDefFailure(['let RefAny: func(): any', 'RefAny = FuncNoArgNoRet'], 'E1012: type mismatch, expected func(): any but got func()')
|
||||
CheckDefFailure(['let RefAny: func(): any', 'RefAny = FuncOneArgNoRet'], 'E1012: type mismatch, expected func(): any but got func(number)')
|
||||
CheckDefFailure(['let RefAny: func(): any', 'RefAny = FuncNoArgNoRet'], 'E1012: Type mismatch; expected func(): any but got func()')
|
||||
CheckDefFailure(['let RefAny: func(): any', 'RefAny = FuncOneArgNoRet'], 'E1012: Type mismatch; expected func(): any but got func(number)')
|
||||
|
||||
let RefNr: func: number
|
||||
RefNr = FuncNoArgRetNumber
|
||||
RefNr = FuncOneArgRetNumber
|
||||
CheckDefFailure(['let RefNr: func: number', 'RefNr = FuncNoArgNoRet'], 'E1012: type mismatch, expected func(): number but got func()')
|
||||
CheckDefFailure(['let RefNr: func: number', 'RefNr = FuncNoArgRetString'], 'E1012: type mismatch, expected func(): number but got func(): string')
|
||||
CheckDefFailure(['let RefNr: func: number', 'RefNr = FuncNoArgNoRet'], 'E1012: Type mismatch; expected func(...): number but got func()')
|
||||
CheckDefFailure(['let RefNr: func: number', 'RefNr = FuncNoArgRetString'], 'E1012: Type mismatch; expected func(...): number but got func(): string')
|
||||
|
||||
let RefStr: func: string
|
||||
RefStr = FuncNoArgRetString
|
||||
RefStr = FuncOneArgRetString
|
||||
CheckDefFailure(['let RefStr: func: string', 'RefStr = FuncNoArgNoRet'], 'E1012: type mismatch, expected func(): string but got func()')
|
||||
CheckDefFailure(['let RefStr: func: string', 'RefStr = FuncNoArgRetNumber'], 'E1012: type mismatch, expected func(): string but got func(): number')
|
||||
CheckDefFailure(['let RefStr: func: string', 'RefStr = FuncNoArgNoRet'], 'E1012: Type mismatch; expected func(...): string but got func()')
|
||||
CheckDefFailure(['let RefStr: func: string', 'RefStr = FuncNoArgRetNumber'], 'E1012: Type mismatch; expected func(...): string but got func(): number')
|
||||
enddef
|
||||
|
||||
def Test_func_type_fails()
|
||||
CheckDefFailure(['let ref1: func()'], 'E704:')
|
||||
|
||||
CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncNoArgRetNumber'], 'E1012: type mismatch, expected func() but got func(): number')
|
||||
CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncOneArgNoRet'], 'E1012: type mismatch, expected func() but got func(number)')
|
||||
CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncOneArgRetNumber'], 'E1012: type mismatch, expected func() but got func(number): number')
|
||||
CheckDefFailure(['let Ref1: func(bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1012: type mismatch, expected func(bool) but got func(bool, number)')
|
||||
CheckDefFailure(['let Ref1: func(?bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1012: type mismatch, expected func(?bool) but got func(bool, number)')
|
||||
CheckDefFailure(['let Ref1: func(...bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1012: type mismatch, expected func(...bool) but got func(bool, number)')
|
||||
CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncNoArgRetNumber'], 'E1012: Type mismatch; expected func() but got func(): number')
|
||||
CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncOneArgNoRet'], 'E1012: Type mismatch; expected func() but got func(number)')
|
||||
CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncOneArgRetNumber'], 'E1012: Type mismatch; expected func() but got func(number): number')
|
||||
CheckDefFailure(['let Ref1: func(bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1012: Type mismatch; expected func(bool) but got func(bool, number)')
|
||||
CheckDefFailure(['let Ref1: func(?bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1012: Type mismatch; expected func(?bool) but got func(bool, number)')
|
||||
CheckDefFailure(['let Ref1: func(...bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1012: Type mismatch; expected func(...bool) but got func(bool, number)')
|
||||
|
||||
CheckDefFailure(['let RefWrong: func(string ,number)'], 'E1068:')
|
||||
CheckDefFailure(['let RefWrong: func(string,number)'], 'E1069:')
|
||||
@@ -1026,7 +1026,7 @@ def Test_func_return_type()
|
||||
str = FuncOneArgRetAny('yes')
|
||||
str->assert_equal('yes')
|
||||
|
||||
CheckDefFailure(['let str: string', 'str = FuncNoArgRetNumber()'], 'E1012: type mismatch, expected string but got number')
|
||||
CheckDefFailure(['let str: string', 'str = FuncNoArgRetNumber()'], 'E1012: Type mismatch; expected string but got number')
|
||||
enddef
|
||||
|
||||
def MultiLine(
|
||||
@@ -1204,7 +1204,7 @@ def ReadRef(Ref: func(): list<string>): string
|
||||
return join(Ref(), ' ')
|
||||
enddef
|
||||
|
||||
def ExtendRef(Ref: func(string), add: string)
|
||||
def ExtendRef(Ref: func(string): list<string>, add: string)
|
||||
Ref(add)
|
||||
enddef
|
||||
|
||||
@@ -1408,7 +1408,7 @@ def Wrong_dict_key_type(items: list<number>): list<number>
|
||||
enddef
|
||||
|
||||
def Test_wrong_dict_key_type()
|
||||
assert_fails('Wrong_dict_key_type([1, 2, 3])', 'E1029:')
|
||||
assert_fails('Wrong_dict_key_type([1, 2, 3])', 'E1012:')
|
||||
enddef
|
||||
|
||||
def Line_continuation_in_def(dir: string = ''): string
|
||||
@@ -1422,7 +1422,7 @@ def Test_line_continuation_in_def()
|
||||
Line_continuation_in_def('.')->assert_equal('full')
|
||||
enddef
|
||||
|
||||
def Line_continuation_in_lambda(): list<number>
|
||||
def Line_continuation_in_lambda(): list<string>
|
||||
let x = range(97, 100)
|
||||
->map({_, v -> nr2char(v)
|
||||
->toupper()})
|
||||
|
@@ -180,9 +180,9 @@ def Test_assignment()
|
||||
CheckDefFailure(['¬ex += 3'], 'E113:')
|
||||
CheckDefFailure(['&ts ..= "xxx"'], 'E1019:')
|
||||
CheckDefFailure(['&ts = [7]'], 'E1012:')
|
||||
CheckDefExecFailure(['&ts = g:alist'], 'E1029: Expected number but got list')
|
||||
CheckDefExecFailure(['&ts = g:alist'], 'E1012: Type mismatch; expected number but got list<number>')
|
||||
CheckDefFailure(['&ts = "xx"'], 'E1012:')
|
||||
CheckDefExecFailure(['&ts = g:astring'], 'E1029: Expected number but got string')
|
||||
CheckDefExecFailure(['&ts = g:astring'], 'E1012: Type mismatch; expected number but got string')
|
||||
CheckDefFailure(['&path += 3'], 'E1012:')
|
||||
CheckDefExecFailure(['&bs = "asdf"'], 'E474:')
|
||||
# test freeing ISN_STOREOPT
|
||||
@@ -958,14 +958,14 @@ def Test_try_catch()
|
||||
try
|
||||
# string slice returns a string, not a number
|
||||
n = g:astring[3]
|
||||
catch /E1029:/
|
||||
catch /E1012:/
|
||||
n = 77
|
||||
endtry
|
||||
assert_equal(77, n)
|
||||
|
||||
try
|
||||
n = l[g:astring]
|
||||
catch /E1029:/
|
||||
catch /E1012:/
|
||||
n = 88
|
||||
endtry
|
||||
assert_equal(88, n)
|
||||
@@ -1016,7 +1016,7 @@ def Test_try_catch()
|
||||
let nd: dict<any>
|
||||
try
|
||||
nd = {g:anumber: 1}
|
||||
catch /E1029:/
|
||||
catch /E1012:/
|
||||
n = 266
|
||||
endtry
|
||||
assert_equal(266, n)
|
||||
@@ -1030,7 +1030,7 @@ def Test_try_catch()
|
||||
|
||||
try
|
||||
&ts = g:astring
|
||||
catch /E1029:/
|
||||
catch /E1012:/
|
||||
n = 288
|
||||
endtry
|
||||
assert_equal(288, n)
|
||||
@@ -3184,6 +3184,24 @@ def Test_let_type_check()
|
||||
CheckScriptSuccess(lines)
|
||||
enddef
|
||||
|
||||
let g:dict_number = #{one: 1, two: 2}
|
||||
|
||||
def Test_let_list_dict_type()
|
||||
let ll: list<number>
|
||||
ll = [1, 2, 2, 3, 3, 3]->uniq()
|
||||
ll->assert_equal([1, 2, 3])
|
||||
|
||||
let dd: dict<number>
|
||||
dd = g:dict_number
|
||||
dd->assert_equal(g:dict_number)
|
||||
|
||||
let lines =<< trim END
|
||||
let ll: list<number>
|
||||
ll = [1, 2, 3]->map('"one"')
|
||||
END
|
||||
CheckDefExecFailure(lines, 'E1012: Type mismatch; expected list<number> but got list<string>')
|
||||
enddef
|
||||
|
||||
def Test_forward_declaration()
|
||||
let lines =<< trim END
|
||||
vim9script
|
||||
|
@@ -750,6 +750,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
1691,
|
||||
/**/
|
||||
1690,
|
||||
/**/
|
||||
|
@@ -207,7 +207,7 @@ typedef struct {
|
||||
|
||||
// arguments to ISN_CHECKTYPE
|
||||
typedef struct {
|
||||
vartype_T ct_type;
|
||||
type_T *ct_type;
|
||||
int ct_off; // offset in stack, -1 is bottom
|
||||
} checktype_T;
|
||||
|
||||
|
@@ -704,7 +704,10 @@ generate_2BOOL(cctx_T *cctx, int invert)
|
||||
}
|
||||
|
||||
static int
|
||||
generate_TYPECHECK(cctx_T *cctx, type_T *vartype, int offset)
|
||||
generate_TYPECHECK(
|
||||
cctx_T *cctx,
|
||||
type_T *expected,
|
||||
int offset)
|
||||
{
|
||||
isn_T *isn;
|
||||
garray_T *stack = &cctx->ctx_type_stack;
|
||||
@@ -712,19 +715,18 @@ generate_TYPECHECK(cctx_T *cctx, type_T *vartype, int offset)
|
||||
RETURN_OK_IF_SKIP(cctx);
|
||||
if ((isn = generate_instr(cctx, ISN_CHECKTYPE)) == NULL)
|
||||
return FAIL;
|
||||
// TODO: whole type, e.g. for a function also arg and return types
|
||||
isn->isn_arg.type.ct_type = vartype->tt_type;
|
||||
isn->isn_arg.type.ct_type = alloc_type(expected);
|
||||
isn->isn_arg.type.ct_off = offset;
|
||||
|
||||
// type becomes vartype
|
||||
((type_T **)stack->ga_data)[stack->ga_len + offset] = vartype;
|
||||
// type becomes expected
|
||||
((type_T **)stack->ga_data)[stack->ga_len + offset] = expected;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that
|
||||
* - "actual" is "expected" type or
|
||||
* - "actual" matches "expected" type or
|
||||
* - "actual" is a type that can be "expected" type: add a runtime check; or
|
||||
* - return FAIL.
|
||||
*/
|
||||
@@ -747,17 +749,29 @@ need_type(
|
||||
|
||||
if (check_type(expected, actual, FALSE, 0) == OK)
|
||||
return OK;
|
||||
if (actual->tt_type != VAR_ANY
|
||||
&& actual->tt_type != VAR_UNKNOWN
|
||||
&& !(actual->tt_type == VAR_FUNC
|
||||
&& (actual->tt_member == &t_any || actual->tt_argcount < 0)))
|
||||
|
||||
// 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 (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))
|
||||
|| (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))
|
||||
{
|
||||
if (!silent)
|
||||
type_mismatch(expected, actual);
|
||||
return FAIL;
|
||||
generate_TYPECHECK(cctx, expected, offset);
|
||||
return OK;
|
||||
}
|
||||
generate_TYPECHECK(cctx, expected, offset);
|
||||
return OK;
|
||||
|
||||
if (!silent)
|
||||
type_mismatch(expected, actual);
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -776,7 +790,7 @@ generate_PUSHNR(cctx_T *cctx, varnumber_T number)
|
||||
|
||||
if (number == 0 || number == 1)
|
||||
{
|
||||
type_T *type = alloc_type(cctx->ctx_type_list);
|
||||
type_T *type = get_type_ptr(cctx->ctx_type_list);
|
||||
|
||||
// A 0 or 1 number can also be used as a bool.
|
||||
if (type != NULL)
|
||||
@@ -4037,7 +4051,7 @@ compile_and_or(
|
||||
typep = ((type_T **)stack->ga_data) + stack->ga_len - 1;
|
||||
if (*typep != &t_bool)
|
||||
{
|
||||
type_T *type = alloc_type(cctx->ctx_type_list);
|
||||
type_T *type = get_type_ptr(cctx->ctx_type_list);
|
||||
|
||||
if (type != NULL)
|
||||
{
|
||||
@@ -7290,6 +7304,10 @@ delete_instr(isn_T *isn)
|
||||
}
|
||||
break;
|
||||
|
||||
case ISN_CHECKTYPE:
|
||||
free_type(isn->isn_arg.type.ct_type);
|
||||
break;
|
||||
|
||||
case ISN_2BOOL:
|
||||
case ISN_2STRING:
|
||||
case ISN_2STRING_ANY:
|
||||
@@ -7301,7 +7319,6 @@ delete_instr(isn_T *isn)
|
||||
case ISN_CATCH:
|
||||
case ISN_CHECKLEN:
|
||||
case ISN_CHECKNR:
|
||||
case ISN_CHECKTYPE:
|
||||
case ISN_COMPAREANY:
|
||||
case ISN_COMPAREBLOB:
|
||||
case ISN_COMPAREBOOL:
|
||||
|
@@ -2535,30 +2535,19 @@ call_def_function(
|
||||
checktype_T *ct = &iptr->isn_arg.type;
|
||||
|
||||
tv = STACK_TV_BOT(ct->ct_off);
|
||||
// TODO: better type comparison
|
||||
if (tv->v_type != ct->ct_type
|
||||
&& !((tv->v_type == VAR_PARTIAL
|
||||
&& ct->ct_type == VAR_FUNC)
|
||||
|| (tv->v_type == VAR_FUNC
|
||||
&& ct->ct_type == VAR_PARTIAL)))
|
||||
SOURCING_LNUM = iptr->isn_lnum;
|
||||
if (check_typval_type(ct->ct_type, tv, 0) == FAIL)
|
||||
goto on_error;
|
||||
|
||||
// number 0 is FALSE, number 1 is TRUE
|
||||
if (tv->v_type == VAR_NUMBER
|
||||
&& ct->ct_type->tt_type == VAR_BOOL
|
||||
&& (tv->vval.v_number == 0
|
||||
|| tv->vval.v_number == 1))
|
||||
{
|
||||
if (tv->v_type == VAR_NUMBER && ct->ct_type == VAR_BOOL
|
||||
&& (tv->vval.v_number == 0
|
||||
|| tv->vval.v_number == 1))
|
||||
{
|
||||
// number 0 is FALSE, number 1 is TRUE
|
||||
tv->v_type = VAR_BOOL;
|
||||
tv->vval.v_number = tv->vval.v_number
|
||||
tv->v_type = VAR_BOOL;
|
||||
tv->vval.v_number = tv->vval.v_number
|
||||
? VVAL_TRUE : VVAL_FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
SOURCING_LNUM = iptr->isn_lnum;
|
||||
semsg(_(e_expected_str_but_got_str),
|
||||
vartype_name(ct->ct_type),
|
||||
vartype_name(tv->v_type));
|
||||
goto on_error;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -3286,10 +3275,16 @@ ex_disassemble(exarg_T *eap)
|
||||
case ISN_NEGATENR: smsg("%4d NEGATENR", current); break;
|
||||
|
||||
case ISN_CHECKNR: smsg("%4d CHECKNR", current); break;
|
||||
case ISN_CHECKTYPE: smsg("%4d CHECKTYPE %s stack[%d]", current,
|
||||
vartype_name(iptr->isn_arg.type.ct_type),
|
||||
iptr->isn_arg.type.ct_off);
|
||||
break;
|
||||
case ISN_CHECKTYPE:
|
||||
{
|
||||
char *tofree;
|
||||
|
||||
smsg("%4d CHECKTYPE %s stack[%d]", current,
|
||||
type_name(iptr->isn_arg.type.ct_type, &tofree),
|
||||
iptr->isn_arg.type.ct_off);
|
||||
vim_free(tofree);
|
||||
break;
|
||||
}
|
||||
case ISN_CHECKLEN: smsg("%4d CHECKLEN %s%d", current,
|
||||
iptr->isn_arg.checklen.cl_more_OK ? ">= " : "",
|
||||
iptr->isn_arg.checklen.cl_min_len);
|
||||
|
109
src/vim9type.c
109
src/vim9type.c
@@ -22,10 +22,10 @@
|
||||
|
||||
/*
|
||||
* Allocate memory for a type_T and add the pointer to type_gap, so that it can
|
||||
* be freed later.
|
||||
* be easily freed later.
|
||||
*/
|
||||
type_T *
|
||||
alloc_type(garray_T *type_gap)
|
||||
get_type_ptr(garray_T *type_gap)
|
||||
{
|
||||
type_T *type;
|
||||
|
||||
@@ -48,6 +48,60 @@ clear_type_list(garray_T *gap)
|
||||
ga_clear(gap);
|
||||
}
|
||||
|
||||
/*
|
||||
* Take a type that is using entries in a growarray and turn it into a type
|
||||
* with allocated entries.
|
||||
*/
|
||||
type_T *
|
||||
alloc_type(type_T *type)
|
||||
{
|
||||
type_T *ret;
|
||||
|
||||
if (type == NULL)
|
||||
return NULL;
|
||||
|
||||
// A fixed type never contains allocated types, return as-is.
|
||||
if (type->tt_flags & TTFLAG_STATIC)
|
||||
return type;
|
||||
|
||||
ret = ALLOC_ONE(type_T);
|
||||
*ret = *type;
|
||||
|
||||
if (ret->tt_member != NULL)
|
||||
ret->tt_member = alloc_type(ret->tt_member);
|
||||
if (type->tt_args != NULL)
|
||||
{
|
||||
int i;
|
||||
|
||||
ret->tt_args = ALLOC_MULT(type_T *, type->tt_argcount);
|
||||
if (ret->tt_args != NULL)
|
||||
for (i = 0; i < type->tt_argcount; ++i)
|
||||
ret->tt_args[i] = alloc_type(type->tt_args[i]);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free a type that was created with alloc_type().
|
||||
*/
|
||||
void
|
||||
free_type(type_T *type)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (type == NULL || (type->tt_flags & TTFLAG_STATIC))
|
||||
return;
|
||||
if (type->tt_args != NULL)
|
||||
{
|
||||
for (i = 0; i < type->tt_argcount; ++i)
|
||||
free_type(type->tt_args[i]);
|
||||
vim_free(type->tt_args);
|
||||
}
|
||||
free_type(type->tt_member);
|
||||
vim_free(type);
|
||||
}
|
||||
|
||||
type_T *
|
||||
get_list_type(type_T *member_type, garray_T *type_gap)
|
||||
{
|
||||
@@ -67,7 +121,7 @@ get_list_type(type_T *member_type, garray_T *type_gap)
|
||||
return &t_list_string;
|
||||
|
||||
// Not a common type, create a new entry.
|
||||
type = alloc_type(type_gap);
|
||||
type = get_type_ptr(type_gap);
|
||||
if (type == NULL)
|
||||
return &t_any;
|
||||
type->tt_type = VAR_LIST;
|
||||
@@ -96,7 +150,7 @@ get_dict_type(type_T *member_type, garray_T *type_gap)
|
||||
return &t_dict_string;
|
||||
|
||||
// Not a common type, create a new entry.
|
||||
type = alloc_type(type_gap);
|
||||
type = get_type_ptr(type_gap);
|
||||
if (type == NULL)
|
||||
return &t_any;
|
||||
type->tt_type = VAR_DICT;
|
||||
@@ -112,7 +166,7 @@ get_dict_type(type_T *member_type, garray_T *type_gap)
|
||||
type_T *
|
||||
alloc_func_type(type_T *ret_type, int argcount, garray_T *type_gap)
|
||||
{
|
||||
type_T *type = alloc_type(type_gap);
|
||||
type_T *type = get_type_ptr(type_gap);
|
||||
|
||||
if (type == NULL)
|
||||
return &t_any;
|
||||
@@ -197,13 +251,14 @@ func_type_add_arg_types(
|
||||
|
||||
/*
|
||||
* Get a type_T for a typval_T.
|
||||
* "type_list" is used to temporarily create types in.
|
||||
* "type_gap" is used to temporarily create types in.
|
||||
*/
|
||||
static type_T *
|
||||
typval2type_int(typval_T *tv, garray_T *type_gap)
|
||||
{
|
||||
type_T *type;
|
||||
type_T *member_type;
|
||||
type_T *member_type = &t_any;
|
||||
int argcount = 0;
|
||||
|
||||
if (tv->v_type == VAR_NUMBER)
|
||||
return &t_number;
|
||||
@@ -262,8 +317,18 @@ typval2type_int(typval_T *tv, garray_T *type_gap)
|
||||
else
|
||||
name = tv->vval.v_string;
|
||||
if (name != NULL)
|
||||
// TODO: how about a builtin function?
|
||||
ufunc = find_func(name, FALSE, NULL);
|
||||
{
|
||||
int idx = find_internal_func(name);
|
||||
|
||||
if (idx >= 0)
|
||||
{
|
||||
// TODO: get actual arg count and types
|
||||
argcount = -1;
|
||||
member_type = internal_func_ret_type(idx, 0, NULL);
|
||||
}
|
||||
else
|
||||
ufunc = find_func(name, FALSE, NULL);
|
||||
}
|
||||
if (ufunc != NULL)
|
||||
{
|
||||
// May need to get the argument types from default values by
|
||||
@@ -276,11 +341,12 @@ typval2type_int(typval_T *tv, garray_T *type_gap)
|
||||
}
|
||||
}
|
||||
|
||||
type = alloc_type(type_gap);
|
||||
type = get_type_ptr(type_gap);
|
||||
if (type == NULL)
|
||||
return NULL;
|
||||
type->tt_type = tv->v_type;
|
||||
type->tt_member = &t_any;
|
||||
type->tt_argcount = argcount;
|
||||
type->tt_member = member_type;
|
||||
|
||||
return type;
|
||||
}
|
||||
@@ -311,7 +377,7 @@ typval2type(typval_T *tv, garray_T *type_gap)
|
||||
&& (tv->vval.v_number == 0 || tv->vval.v_number == 1))
|
||||
|| (tv->v_lock & VAR_BOOL_OK)))
|
||||
{
|
||||
type_T *newtype = alloc_type(type_gap);
|
||||
type_T *newtype = get_type_ptr(type_gap);
|
||||
|
||||
// Number 0 and 1 and expression with "&&" or "||" can also be used
|
||||
// for bool.
|
||||
@@ -420,6 +486,7 @@ check_type(type_T *expected, type_T *actual, int give_msg, int argidx)
|
||||
ret = check_type(expected->tt_member, actual->tt_member,
|
||||
FALSE, 0);
|
||||
if (ret == OK && expected->tt_argcount != -1
|
||||
&& actual->tt_argcount != -1
|
||||
&& (actual->tt_argcount < expected->tt_min_argcount
|
||||
|| actual->tt_argcount > expected->tt_argcount))
|
||||
ret = FAIL;
|
||||
@@ -940,7 +1007,6 @@ type_name(type_T *type, char **tofree)
|
||||
ga_init2(&ga, 1, 100);
|
||||
if (ga_grow(&ga, 20) == FAIL)
|
||||
return "[unknown]";
|
||||
*tofree = ga.ga_data;
|
||||
STRCPY(ga.ga_data, "func(");
|
||||
ga.ga_len += 5;
|
||||
|
||||
@@ -963,20 +1029,19 @@ type_name(type_T *type, char **tofree)
|
||||
if (ga_grow(&ga, len + 8) == FAIL)
|
||||
{
|
||||
vim_free(arg_free);
|
||||
ga_clear(&ga);
|
||||
return "[unknown]";
|
||||
}
|
||||
*tofree = ga.ga_data;
|
||||
if (varargs && i == type->tt_argcount - 1)
|
||||
{
|
||||
STRCPY((char *)ga.ga_data + ga.ga_len, "...");
|
||||
ga.ga_len += 3;
|
||||
}
|
||||
ga_concat(&ga, (char_u *)"...");
|
||||
else if (i >= type->tt_min_argcount)
|
||||
*((char *)ga.ga_data + ga.ga_len++) = '?';
|
||||
STRCPY((char *)ga.ga_data + ga.ga_len, arg_type);
|
||||
ga.ga_len += len;
|
||||
ga_concat(&ga, (char_u *)arg_type);
|
||||
vim_free(arg_free);
|
||||
}
|
||||
if (type->tt_argcount < 0)
|
||||
// any number of arguments
|
||||
ga_concat(&ga, (char_u *)"...");
|
||||
|
||||
if (type->tt_member == &t_void)
|
||||
STRCPY((char *)ga.ga_data + ga.ga_len, ")");
|
||||
@@ -990,18 +1055,18 @@ type_name(type_T *type, char **tofree)
|
||||
if (ga_grow(&ga, len) == FAIL)
|
||||
{
|
||||
vim_free(ret_free);
|
||||
ga_clear(&ga);
|
||||
return "[unknown]";
|
||||
}
|
||||
*tofree = ga.ga_data;
|
||||
STRCPY((char *)ga.ga_data + ga.ga_len, "): ");
|
||||
STRCPY((char *)ga.ga_data + ga.ga_len + 3, ret_name);
|
||||
vim_free(ret_free);
|
||||
}
|
||||
*tofree = ga.ga_data;
|
||||
return ga.ga_data;
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
#endif // FEAT_EVAL
|
||||
|
Reference in New Issue
Block a user