]> granicus.if.org Git - vim/commitdiff
patch 8.2.1691: Vim9: list<any> is not accepted where list<number> is expected v8.2.1691
authorBram Moolenaar <Bram@vim.org>
Wed, 16 Sep 2020 13:22:00 +0000 (15:22 +0200)
committerBram Moolenaar <Bram@vim.org>
Wed, 16 Sep 2020 13:22:00 +0000 (15:22 +0200)
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)

13 files changed:
src/errors.h
src/evalfunc.c
src/globals.h
src/proto/vim9type.pro
src/testdir/test_vim9_disassemble.vim
src/testdir/test_vim9_expr.vim
src/testdir/test_vim9_func.vim
src/testdir/test_vim9_script.vim
src/version.c
src/vim9.h
src/vim9compile.c
src/vim9execute.c
src/vim9type.c

index badbabd3aac9db5b9534c2f5b323386ee6dbc490..a30ddcaacf28b4eae4f0dff968c3be407541ea95 100644 (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[]
index 533f5b95dda10297886721d76e8db50cb69418a9..f96a4c44d1c078037a148f22cdfbf0fbf6990468 100644 (file)
@@ -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;
 }
 
 /*
index 337c0689fc37e1a8315ae6779670d5222a058e2f..94164bbc3c855adfdb08f04969524e461622fcf8 100644 (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_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
 
index 1492488002d02ea3c805e41c94258316a2d1596f..e80f303a4dc726c1468e4728e291a50cc5422503 100644 (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);
index 78d0a62aadc595d77951222f65f2635679bc2bfd..7fd8c062b195d34cbd69f36a32f6357a1e8ddbac 100644 (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())
index b09242e91cc8e89f1a17ca172b7455bc0c4b703e..ff0c75d42ceb8c5f104001988293835fac471f02 100644 (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
 
index de107249eb331fd6776c24390ecc035c50c786e7..563e281a08634d811f115c11723459b0bc7cf8af 100644 (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()})
index 936c7dd1957db57d4be3799705b3412c44fac70a..bb2bfaf75bc16114f8f100142a77839b9fb37a6f 100644 (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
index 6aa02b47445ba7c829962f90f10c2dc047688071..2154ddd77971c46d9614335404fabd92b6021d48 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1691,
 /**/
     1690,
 /**/
index 310b59e719889618b63232e7e12b10076f4f2ffe..b3d5bc226a04ac5d4c1a21630604a086bb7ac228 100644 (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;
 
index a53f05d323662f81339798c89980a36d9d1918e1..075bd12c4507dbc511c083a2a457aa79b4654b74 100644 (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,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:
index cd6990f90db12d396c1af02840273352a4f7b91f..ddc20bce8f218774ba6deb0afd2883675d2b7aeb 100644 (file)
@@ -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);
index 637032d3483cdadbaec9ac38da5e368dafda2c56..cc879d0e7526ed9d7e18b3542cc1c5d6e9ee9fe5 100644 (file)
 
 /*
  * 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