0
0
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:
Bram Moolenaar
2020-09-16 15:22:00 +02:00
parent 8b51b7f0f1
commit 5e65423077
13 changed files with 253 additions and 149 deletions

View File

@@ -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[]

View File

@@ -385,12 +385,15 @@ ret_argv(int argcount, type_T **argtypes UNUSED)
static type_T *
ret_remove(int argcount UNUSED, type_T **argtypes)
{
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;
}
/*

View File

@@ -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

View File

@@ -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);

View File

@@ -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())

View File

@@ -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

View File

@@ -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()})

View File

@@ -180,9 +180,9 @@ def Test_assignment()
CheckDefFailure(['&notex += 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

View File

@@ -750,6 +750,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
1691,
/**/
1690,
/**/

View File

@@ -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;

View File

@@ -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,18 +749,30 @@ 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))
{
generate_TYPECHECK(cctx, expected, offset);
return OK;
}
if (!silent)
type_mismatch(expected, actual);
return FAIL;
}
generate_TYPECHECK(cctx, expected, offset);
return OK;
}
/*
* Generate an ISN_PUSHNR instruction.
@@ -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:

View File

@@ -2535,31 +2535,20 @@ 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)))
{
if (tv->v_type == VAR_NUMBER && ct->ct_type == VAR_BOOL
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))
{
// number 0 is FALSE, number 1 is TRUE
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),
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);

View File

@@ -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?
{
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