summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2020-09-16 15:22:00 +0200
committerBram Moolenaar <Bram@vim.org>2020-09-16 15:22:00 +0200
commit5e654230777ad21363a929dce3cfe0387da031a7 (patch)
tree967aea5363b039cb47c98bf2ef2e992f182b29da
parent8b51b7f0f17af149a8ce76e805050977857f9e50 (diff)
downloadvim-git-5e654230777ad21363a929dce3cfe0387da031a7.tar.gz
patch 8.2.1691: Vim9: list<any> is not accepted where list<number> is expectedv8.2.1691
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)
-rw-r--r--src/errors.h2
-rw-r--r--src/evalfunc.c15
-rw-r--r--src/globals.h71
-rw-r--r--src/proto/vim9type.pro4
-rw-r--r--src/testdir/test_vim9_disassemble.vim6
-rw-r--r--src/testdir/test_vim9_expr.vim29
-rw-r--r--src/testdir/test_vim9_func.vim40
-rw-r--r--src/testdir/test_vim9_script.vim30
-rw-r--r--src/version.c2
-rw-r--r--src/vim9.h2
-rw-r--r--src/vim9compile.c55
-rw-r--r--src/vim9execute.c47
-rw-r--r--src/vim9type.c109
13 files changed, 258 insertions, 154 deletions
diff --git a/src/errors.h b/src/errors.h
index badbabd3a..a30ddcaac 100644
--- a/src/errors.h
+++ b/src/errors.h
@@ -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[]
diff --git a/src/evalfunc.c b/src/evalfunc.c
index 533f5b95d..f96a4c44d 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -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;
}
/*
diff --git a/src/globals.h b/src/globals.h
index 337c0689f..94164bbc3 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -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_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_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_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_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, 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, 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, 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
diff --git a/src/proto/vim9type.pro b/src/proto/vim9type.pro
index 149248800..e80f303a4 100644
--- a/src/proto/vim9type.pro
+++ b/src/proto/vim9type.pro
@@ -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);
diff --git a/src/testdir/test_vim9_disassemble.vim b/src/testdir/test_vim9_disassemble.vim
index 78d0a62aa..7fd8c062b 100644
--- a/src/testdir/test_vim9_disassemble.vim
+++ b/src/testdir/test_vim9_disassemble.vim
@@ -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())
diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim
index b09242e91..ff0c75d42 100644
--- a/src/testdir/test_vim9_expr.vim
+++ b/src/testdir/test_vim9_expr.vim
@@ -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
diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim
index de107249e..563e281a0 100644
--- a/src/testdir/test_vim9_func.vim
+++ b/src/testdir/test_vim9_func.vim
@@ -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()})
diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim
index 936c7dd19..bb2bfaf75 100644
--- a/src/testdir/test_vim9_script.vim
+++ b/src/testdir/test_vim9_script.vim
@@ -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
diff --git a/src/version.c b/src/version.c
index 6aa02b474..2154ddd77 100644
--- a/src/version.c
+++ b/src/version.c
@@ -751,6 +751,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1691,
+/**/
1690,
/**/
1689,
diff --git a/src/vim9.h b/src/vim9.h
index 310b59e71..b3d5bc226 100644
--- a/src/vim9.h
+++ b/src/vim9.h
@@ -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;
diff --git a/src/vim9compile.c b/src/vim9compile.c
index a53f05d32..075bd12c4 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -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 (!silent)
- type_mismatch(expected, actual);
- return FAIL;
+
+ // 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;
}
- 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:
diff --git a/src/vim9execute.c b/src/vim9execute.c
index cd6990f90..ddc20bce8 100644
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -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);
diff --git a/src/vim9type.c b/src/vim9type.c
index 637032d34..cc879d0e7 100644
--- a/src/vim9type.c
+++ b/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