diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 74ae9798d7..f9d2e14c3f 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -1684,7 +1684,7 @@ pub fn (mut c Checker) method_call(mut call_expr ast.CallExpr) ast.Type { if method.generic_names.len > 0 { continue } - c.check_expected_call_arg(got_arg_typ, exp_arg_typ, call_expr.language) or { + c.check_expected_call_arg(got_arg_typ, c.unwrap_generic(exp_arg_typ), call_expr.language) or { // str method, allow type with str method if fn arg is string // Passing an int or a string array produces a c error here // Deleting this condition results in propper V error messages @@ -1758,16 +1758,17 @@ pub fn (mut c Checker) method_call(mut call_expr ast.CallExpr) ast.Type { if method.generic_names.len != call_expr.concrete_types.len { // no type arguments given in call, attempt implicit instantiation c.infer_fn_generic_types(method, mut call_expr) + concrete_types = call_expr.concrete_types } // resolve return generics struct to concrete type if method.generic_names.len > 0 && method.return_type.has_flag(.generic) { - c.check_return_generics_struct(method.return_type, mut call_expr, call_expr.concrete_types) + c.check_return_generics_struct(method.return_type, mut call_expr, concrete_types) } else { call_expr.return_type = method.return_type } if call_expr.concrete_types.len > 0 && method.return_type != 0 { if typ := c.table.resolve_generic_to_concrete(method.return_type, method.generic_names, - call_expr.concrete_types, false) + concrete_types, false) { call_expr.return_type = typ return typ @@ -2248,7 +2249,7 @@ pub fn (mut c Checker) fn_call(mut call_expr ast.CallExpr) ast.Type { c.type_implements(typ, param.typ, call_arg.expr.position()) continue } - c.check_expected_call_arg(typ, param.typ, call_expr.language) or { + c.check_expected_call_arg(typ, c.unwrap_generic(param.typ), call_expr.language) or { // str method, allow type with str method if fn arg is string // Passing an int or a string array produces a c error here // Deleting this condition results in propper V error messages @@ -2275,6 +2276,7 @@ pub fn (mut c Checker) fn_call(mut call_expr ast.CallExpr) ast.Type { if func.generic_names.len != call_expr.concrete_types.len { // no type arguments given in call, attempt implicit instantiation c.infer_fn_generic_types(func, mut call_expr) + concrete_types = call_expr.concrete_types } if func.generic_names.len > 0 { for i, call_arg in call_expr.args { @@ -2289,9 +2291,9 @@ pub fn (mut c Checker) fn_call(mut call_expr ast.CallExpr) ast.Type { if param.typ.has_flag(.generic) && func.generic_names.len == call_expr.concrete_types.len { if unwrap_typ := c.table.resolve_generic_to_concrete(param.typ, func.generic_names, - call_expr.concrete_types, false) + concrete_types, false) { - c.check_expected_call_arg(typ, unwrap_typ, call_expr.language) or { + c.check_expected_call_arg(c.unwrap_generic(typ), unwrap_typ, call_expr.language) or { c.error('$err.msg in argument ${i + 1} to `$fn_name`', call_arg.pos) } } @@ -2300,13 +2302,13 @@ pub fn (mut c Checker) fn_call(mut call_expr ast.CallExpr) ast.Type { } // resolve return generics struct to concrete type if func.generic_names.len > 0 && func.return_type.has_flag(.generic) { - c.check_return_generics_struct(func.return_type, mut call_expr, call_expr.concrete_types) + c.check_return_generics_struct(func.return_type, mut call_expr, concrete_types) } else { call_expr.return_type = func.return_type } if call_expr.concrete_types.len > 0 && func.return_type != 0 { if typ := c.table.resolve_generic_to_concrete(func.return_type, func.generic_names, - call_expr.concrete_types, false) + concrete_types, false) { call_expr.return_type = typ return typ diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index d44639d694..d92d6b8ec1 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -853,7 +853,15 @@ pub fn (mut g Gen) write_fn_typesymbol_declaration(sym ast.TypeSymbol) { func := info.func is_fn_sig := func.name == '' not_anon := !info.is_anon - if !info.has_decl && (not_anon || is_fn_sig) && !func.return_type.has_flag(.generic) { + mut has_generic_arg := false + for param in func.params { + if param.typ.has_flag(.generic) { + has_generic_arg = true + break + } + } + if !info.has_decl && (not_anon || is_fn_sig) && !func.return_type.has_flag(.generic) + && !has_generic_arg { fn_name := sym.cname g.type_definitions.write_string('typedef ${g.typ(func.return_type)} (*$fn_name)(') for i, param in func.params { diff --git a/vlib/v/tests/generics_with_anon_generics_fn_test.v b/vlib/v/tests/generics_with_anon_generics_fn_test.v new file mode 100644 index 0000000000..706720bea7 --- /dev/null +++ b/vlib/v/tests/generics_with_anon_generics_fn_test.v @@ -0,0 +1,34 @@ +struct MyStruct { + arr []T +} + +fn (mut s MyStruct) get_data(pos int) T { + return s.arr[pos] +} + +fn (mut s MyStruct) iterate(handler fn (T) int) int { + mut sum := 0 + mut i := 0 + for { + k := s.get_data(i) + sum += handler(k) + i++ + if i > 4 { + break + } + } + return sum +} + +pub fn consume(data int) int { + return data +} + +fn test_generics_with_anon_generics_fn() { + mut s := MyStruct{ + arr: [1, 2, 3, 4, 5] + } + y := s.iterate(consume) + println(y) + assert y == 15 +}