]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.0.2057: Vim9: no strict type checks for funcrefs varargs v9.0.2057
authorErnie Rael <errael@raelity.com>
Sat, 21 Oct 2023 09:45:38 +0000 (11:45 +0200)
committerChristian Brabandt <cb@256bit.org>
Sat, 21 Oct 2023 09:45:38 +0000 (11:45 +0200)
Problem:  Vim9: no strict type checks for funcrefs varargs
Solution: Perform strict type checking when declaring funcrefs
          with vararg declaration, add tests

closes: #13397

Signed-off-by: Christian Brabandt <cb@256bit.org>
Co-authored-by: Ernie Rael <errael@raelity.com>
runtime/doc/tags
runtime/doc/vim9.txt
src/testdir/test_vim9_assign.vim
src/testdir/test_vim9_func.vim
src/version.c
src/vim9type.c

index 77b7d1b2dee4ef287df11b72b41ce6c749e9394e..fde5bda1a4a4a4a49ffb4d056fab946e32333e4d 100644 (file)
@@ -11010,6 +11010,7 @@ vim9-differences        vim9.txt        /*vim9-differences*
 vim9-export    vim9.txt        /*vim9-export*
 vim9-false-true        vim9.txt        /*vim9-false-true*
 vim9-final     vim9.txt        /*vim9-final*
+vim9-func-declaration  vim9.txt        /*vim9-func-declaration*
 vim9-function-defined-later    vim9.txt        /*vim9-function-defined-later*
 vim9-gotchas   vim9.txt        /*vim9-gotchas*
 vim9-ignored-argument  vim9.txt        /*vim9-ignored-argument*
index 6cabb870d8dcc6f7803ca2f9f317f762b57fc985..58d9ed614266e793686855a3233c9b458c3edc8a 100644 (file)
@@ -1468,7 +1468,7 @@ return value) results in error *E1031*  *E1186* .
 There is no array type, use list<{type}> instead.  For a list constant an
 efficient implementation is used that avoids allocating a lot of small pieces
 of memory.
-                                                       *E1005* *E1007*
+                                   *vim9-func-declaration* *E1005* *E1007*
 A partial and function can be declared in more or less specific ways:
 func                           any kind of function reference, no type
                                checking for arguments or return value
@@ -1669,6 +1669,26 @@ Same for |extend()|, use |extendnew()| instead, and for |flatten()|, use
 |flattennew()| instead.  Since |flatten()| is intended to always change the
 type, it can not be used in Vim9 script.
 
+Assigning to a funcref with specified arguments (see |vim9-func-declaration|)
+does strict type checking of the arguments. For variable number of arguments
+the type must match: >
+       var FuncRef: func(string, number, bool): number
+       FuncRef = (v1: string, v2: number, v3: bool) => 777     # OK
+       FuncRef = (v1: string, v2: number, v3: number) => 777   # Error!
+       # variable number of arguments must have same type
+       var FuncVA: func(...list<string>): number
+       FuncVA = (...v: list<number>): number => v  # Error!
+       FuncVA = (...v: list<any>): number => v     # OK, `any` runtime check
+       FuncVA = (v1: string, v: string2): number => 333     # Error!
+       FuncVA = (v: list<string>): number => 3     # Error!
+
+If the destinataion funcref has no specified arguments, then there is no
+argument type checking: >
+       var FuncUnknownArgs: func: number
+       FuncUnknownArgs = (v): number => v                      # OK
+       FuncUnknownArgs = (v1: string, v2: string): number => 3 # OK
+<      FuncUnknownArgs = (...v1: list<string>): number => 333  # OK
+
                         *E1211* *E1217* *E1218* *E1219* *E1220* *E1221*
                         *E1222* *E1223* *E1224* *E1225* *E1226* *E1227*
                         *E1228* *E1238* *E1250* *E1251* *E1252* *E1256*
index bff9c9f8f1e788d2dff7d0887739da4e1c893f07..6d2858f6c0372489c6f43ad0766c7495445e6cc9 100644 (file)
@@ -1890,7 +1890,7 @@ def Test_assign_funcref_args()
     var FuncAnyVA: func(...any): number
     FuncAnyVA = (v): number => v
   END
-  v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected func(...any): number but got func(any): number')
+  v9.CheckScriptFailure(lines, 'E1180: Variable arguments type must be a list: any')
 
   # varargs must match
   lines =<< trim END
@@ -1898,7 +1898,7 @@ def Test_assign_funcref_args()
     var FuncAnyVA: func(...any): number
     FuncAnyVA = (v1, v2): number => v1 + v2
   END
-  v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected func(...any): number but got func(any, any): number')
+  v9.CheckScriptFailure(lines, 'E1180: Variable arguments type must be a list: any')
 
   # varargs must match
   lines =<< trim END
@@ -1906,7 +1906,7 @@ def Test_assign_funcref_args()
     var FuncAnyVA: func(...any): number
     FuncAnyVA = (v1: list<any>): number => 3
   END
-  v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected func(...any): number but got func(list<any>): number')
+  v9.CheckScriptFailure(lines, 'E1180: Variable arguments type must be a list: any')
 enddef
 
 def Test_assign_funcref_arg_any()
index 701a2f085dd3a13a8d58e75f6c3ee8700d00c112..cbbd5726403016459946e79a4c320dd082df6392 100644 (file)
@@ -1995,7 +1995,7 @@ def Test_varargs_mismatch()
       var res = Map((v) => str2nr(v))
       assert_equal(12, res)
   END
-  v9.CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected func(...any): number but got func(any): number')
+  v9.CheckScriptFailure(lines, 'E1180: Variable arguments type must be a list: any')
 enddef
 
 def Test_using_var_as_arg()
@@ -2764,7 +2764,7 @@ def Test_func_type_fails()
   v9.CheckDefFailure(['var Ref1: func()', 'Ref1 = g:FuncOneArgRetNumber'], 'E1012: Type mismatch; expected func() but got func(number): number')
   v9.CheckDefFailure(['var Ref1: func(bool)', 'Ref1 = g:FuncTwoArgNoRet'], 'E1012: Type mismatch; expected func(bool) but got func(bool, number)')
   v9.CheckDefFailure(['var Ref1: func(?bool)', 'Ref1 = g:FuncTwoArgNoRet'], 'E1012: Type mismatch; expected func(?bool) but got func(bool, number)')
-  v9.CheckDefFailure(['var Ref1: func(...bool)', 'Ref1 = g:FuncTwoArgNoRet'], 'E1012: Type mismatch; expected func(...bool) but got func(bool, number)')
+  v9.CheckDefFailure(['var Ref1: func(...bool)', 'Ref1 = g:FuncTwoArgNoRet'], 'E1180: Variable arguments type must be a list: bool')
 
   v9.CheckDefFailure(['var RefWrong: func(string ,number)'], 'E1068:')
   v9.CheckDefFailure(['var RefWrong: func(string,number)'], 'E1069:')
index 7584e45fff115c2ccbcdceeebda2fa701855841e..fbf2999dd3976206ec8276fd50eae48c4b22f381 100644 (file)
@@ -704,6 +704,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2057,
 /**/
     2056,
 /**/
index 6a5848792bc90dea11c8dcf59fbb85e98695e729..c31e51b983b1f4cbaa275adbe70dbcdad52ce2f0 100644 (file)
@@ -1231,6 +1231,15 @@ parse_type(char_u **arg, garray_T *type_gap, int give_error)
                        type = parse_type(&p, type_gap, give_error);
                        if (type == NULL)
                            return NULL;
+                       if ((flags & TTFLAG_VARARGS) != 0
+                               && type->tt_type != VAR_LIST)
+                       {
+                           char *tofree;
+                           semsg(_(e_variable_arguments_type_must_be_list_str),
+                                 type_name(type, &tofree));
+                           vim_free(tofree);
+                           return NULL;
+                       }
                        arg_type[argcount++] = type;
 
                        // Nothing comes after "...{type}".