1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

checker: check generic method called with a variadic argument mismatch (fix #16106) (#16110)

This commit is contained in:
yuyi 2022-10-20 20:28:30 +08:00 committed by GitHub
parent 07310d850d
commit f8a28b5a5d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 58 additions and 0 deletions

View File

@ -941,6 +941,7 @@ pub fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool)
typ := c.expr(call_arg.expr) typ := c.expr(call_arg.expr)
if i == node.args.len - 1 { if i == node.args.len - 1 {
if c.table.sym(typ).kind == .array && call_arg.expr !is ast.ArrayDecompose if c.table.sym(typ).kind == .array && call_arg.expr !is ast.ArrayDecompose
&& c.table.sym(expected_type).kind !in [.sum_type, .interface_]
&& !param.typ.has_flag(.generic) && expected_type != typ { && !param.typ.has_flag(.generic) && expected_type != typ {
styp := c.table.type_to_str(typ) styp := c.table.type_to_str(typ)
elem_styp := c.table.type_to_str(expected_type) elem_styp := c.table.type_to_str(expected_type)
@ -1533,6 +1534,42 @@ pub fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
} else { } else {
method.params[i + 1] method.params[i + 1]
} }
if method.is_variadic && arg.expr is ast.ArrayDecompose {
if i > method.params.len - 2 {
c.error('too many arguments in call to `$method.name`', node.pos)
}
}
if method.is_variadic && i >= method.params.len - 2 {
param_sym := c.table.sym(param.typ)
mut expected_type := param.typ
if param_sym.kind == .array {
info := param_sym.array_info()
expected_type = info.elem_type
c.expected_type = expected_type
}
typ := c.expr(arg.expr)
if i == node.args.len - 1 {
if c.table.sym(typ).kind == .array && arg.expr !is ast.ArrayDecompose
&& c.table.sym(expected_type).kind !in [.sum_type, .interface_]
&& !param.typ.has_flag(.generic) && expected_type != typ {
styp := c.table.type_to_str(typ)
elem_styp := c.table.type_to_str(expected_type)
c.error('to pass `$arg.expr` ($styp) to `$method.name` (which accepts type `...$elem_styp`), use `...$arg.expr`',
node.pos)
} else if arg.expr is ast.ArrayDecompose
&& c.table.sym(expected_type).kind == .sum_type
&& expected_type.idx() != typ.idx() {
expected_type_str := c.table.type_to_str(expected_type)
got_type_str := c.table.type_to_str(typ)
c.error('cannot use `...$got_type_str` as `...$expected_type_str` in argument ${
i + 1} to `$method_name`', arg.pos)
}
}
} else {
c.expected_type = param.typ
}
param_is_mut = param_is_mut || param.is_mut param_is_mut = param_is_mut || param.is_mut
param_share := param.typ.share() param_share := param.typ.share()
if param_share == .shared_t && (c.locked_names.len > 0 || c.rlocked_names.len > 0) { if param_share == .shared_t && (c.locked_names.len > 0 || c.rlocked_names.len > 0) {

View File

@ -0,0 +1,7 @@
vlib/v/checker/tests/generics_method_called_variadic_arg_mismatch.vv:8:4: error: to pass `options` (string) to `req` (which accepts type `...string`), use `...options`
6 |
7 | fn (c Client) products_list(options ...string) {
8 | c.req<Product>(options) // (...options) works
| ~~~~~~~~~~~~~~~~~~~~~
9 | }
10 |

View File

@ -0,0 +1,14 @@
struct Client {}
fn (cl Client) req<T>(data ...string) {}
struct Product {}
fn (c Client) products_list(options ...string) {
c.req<Product>(options) // (...options) works
}
fn main() {
mut sc := Client{}
sc.products_list()
}