forked from aniani/vim
patch 9.0.2057: Vim9: no strict type checks for funcrefs varargs
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>
This commit is contained in:
committed by
Christian Brabandt
parent
d3e277f279
commit
3ec6c1fe3b
@@ -11010,6 +11010,7 @@ vim9-differences vim9.txt /*vim9-differences*
|
|||||||
vim9-export vim9.txt /*vim9-export*
|
vim9-export vim9.txt /*vim9-export*
|
||||||
vim9-false-true vim9.txt /*vim9-false-true*
|
vim9-false-true vim9.txt /*vim9-false-true*
|
||||||
vim9-final vim9.txt /*vim9-final*
|
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-function-defined-later vim9.txt /*vim9-function-defined-later*
|
||||||
vim9-gotchas vim9.txt /*vim9-gotchas*
|
vim9-gotchas vim9.txt /*vim9-gotchas*
|
||||||
vim9-ignored-argument vim9.txt /*vim9-ignored-argument*
|
vim9-ignored-argument vim9.txt /*vim9-ignored-argument*
|
||||||
|
@@ -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
|
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
|
efficient implementation is used that avoids allocating a lot of small pieces
|
||||||
of memory.
|
of memory.
|
||||||
*E1005* *E1007*
|
*vim9-func-declaration* *E1005* *E1007*
|
||||||
A partial and function can be declared in more or less specific ways:
|
A partial and function can be declared in more or less specific ways:
|
||||||
func any kind of function reference, no type
|
func any kind of function reference, no type
|
||||||
checking for arguments or return value
|
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
|
|flattennew()| instead. Since |flatten()| is intended to always change the
|
||||||
type, it can not be used in Vim9 script.
|
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*
|
*E1211* *E1217* *E1218* *E1219* *E1220* *E1221*
|
||||||
*E1222* *E1223* *E1224* *E1225* *E1226* *E1227*
|
*E1222* *E1223* *E1224* *E1225* *E1226* *E1227*
|
||||||
*E1228* *E1238* *E1250* *E1251* *E1252* *E1256*
|
*E1228* *E1238* *E1250* *E1251* *E1252* *E1256*
|
||||||
|
@@ -1890,7 +1890,7 @@ def Test_assign_funcref_args()
|
|||||||
var FuncAnyVA: func(...any): number
|
var FuncAnyVA: func(...any): number
|
||||||
FuncAnyVA = (v): number => v
|
FuncAnyVA = (v): number => v
|
||||||
END
|
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
|
# varargs must match
|
||||||
lines =<< trim END
|
lines =<< trim END
|
||||||
@@ -1898,7 +1898,7 @@ def Test_assign_funcref_args()
|
|||||||
var FuncAnyVA: func(...any): number
|
var FuncAnyVA: func(...any): number
|
||||||
FuncAnyVA = (v1, v2): number => v1 + v2
|
FuncAnyVA = (v1, v2): number => v1 + v2
|
||||||
END
|
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
|
# varargs must match
|
||||||
lines =<< trim END
|
lines =<< trim END
|
||||||
@@ -1906,7 +1906,7 @@ def Test_assign_funcref_args()
|
|||||||
var FuncAnyVA: func(...any): number
|
var FuncAnyVA: func(...any): number
|
||||||
FuncAnyVA = (v1: list<any>): number => 3
|
FuncAnyVA = (v1: list<any>): number => 3
|
||||||
END
|
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
|
enddef
|
||||||
|
|
||||||
def Test_assign_funcref_arg_any()
|
def Test_assign_funcref_arg_any()
|
||||||
|
@@ -1995,7 +1995,7 @@ def Test_varargs_mismatch()
|
|||||||
var res = Map((v) => str2nr(v))
|
var res = Map((v) => str2nr(v))
|
||||||
assert_equal(12, res)
|
assert_equal(12, res)
|
||||||
END
|
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
|
enddef
|
||||||
|
|
||||||
def Test_using_var_as_arg()
|
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()', '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'], '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)'], 'E1068:')
|
||||||
v9.CheckDefFailure(['var RefWrong: func(string,number)'], 'E1069:')
|
v9.CheckDefFailure(['var RefWrong: func(string,number)'], 'E1069:')
|
||||||
|
@@ -704,6 +704,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
2057,
|
||||||
/**/
|
/**/
|
||||||
2056,
|
2056,
|
||||||
/**/
|
/**/
|
||||||
|
@@ -1231,6 +1231,15 @@ parse_type(char_u **arg, garray_T *type_gap, int give_error)
|
|||||||
type = parse_type(&p, type_gap, give_error);
|
type = parse_type(&p, type_gap, give_error);
|
||||||
if (type == NULL)
|
if (type == NULL)
|
||||||
return 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;
|
arg_type[argcount++] = type;
|
||||||
|
|
||||||
// Nothing comes after "...{type}".
|
// Nothing comes after "...{type}".
|
||||||
|
Reference in New Issue
Block a user