diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 3e5daaba1264a9..f037c54786316d 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -1872,6 +1872,7 @@ pub mut: func &AnonFn = unsafe { nil } is_checked bool typ Type + call_ctx &CallExpr = unsafe { nil } } pub struct Likely { diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index bcddea101f18ef..1465d812cb170c 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -1585,6 +1585,19 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast. if c.comptime.type_map.len > 0 { continue } + if mut call_arg.expr is ast.LambdaExpr { + // Calling fn is generic and lambda arg also is generic + if node.concrete_types.len > 0 + && call_arg.expr.func.decl.generic_names.len > 0 { + call_arg.expr.call_ctx = unsafe { node } + if c.table.register_fn_concrete_types(call_arg.expr.func.decl.fkey(), + node.concrete_types) + { + call_arg.expr.func.decl.ninstances++ + } + } + continue + } c.error('${err.msg()} in argument ${i + 1} to `${fn_name}`', call_arg.pos) } } diff --git a/vlib/v/checker/lambda_expr.v b/vlib/v/checker/lambda_expr.v index b3cf4c9506cb73..96e40e594a9849 100644 --- a/vlib/v/checker/lambda_expr.v +++ b/vlib/v/checker/lambda_expr.v @@ -127,6 +127,9 @@ pub fn (mut c Checker) lambda_expr_fix_type_of_param(mut node ast.LambdaExpr, mu v.typ = ptype v.is_auto_deref = ptype.is_ptr() v.expr = ast.empty_expr + if ptype.has_flag(.generic) { + v.ct_type_var = .generic_param + } } } if pident.kind != .blank_ident { diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 30a7facdda7857..39cf86c94e6928 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -3565,8 +3565,14 @@ fn (mut g Gen) expr(node_ ast.Expr) { g.write('/*IsRefType*/ ${is_ref_type}') } ast.LambdaExpr { - g.gen_anon_fn(mut node.func) - // g.write('/* lambda expr: ${node_.str()} */') + if node.call_ctx != unsafe { nil } { + save_cur_concrete_types := g.cur_concrete_types + g.cur_concrete_types = node.call_ctx.concrete_types + g.gen_anon_fn(mut node.func) + g.cur_concrete_types = save_cur_concrete_types + } else { + g.gen_anon_fn(mut node.func) + } } ast.Likely { if node.is_likely { diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index e6ee6d88857cb2..f1c52a85847158 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -575,6 +575,7 @@ fn (mut g Gen) closure_ctx(node ast.FnDecl) string { fn (mut g Gen) gen_anon_fn(mut node ast.AnonFn) { g.gen_anon_fn_decl(mut node) mut fn_name := node.decl.name + if node.decl.generic_names.len > 0 { fn_name = g.generic_fn_name(g.cur_concrete_types, fn_name) } @@ -1463,11 +1464,39 @@ fn (mut g Gen) resolve_receiver_name(node ast.CallExpr, unwrapped_rec_type ast.T return receiver_type_name } +fn (mut g Gen) resolve_generic_expr(expr ast.Expr, default_typ ast.Type) ast.Type { + match expr { + ast.ParExpr { + return g.resolve_generic_expr(expr.expr, default_typ) + } + ast.InfixExpr { + if g.comptime.is_comptime_var(expr.left) { + return g.unwrap_generic(g.comptime.get_comptime_var_type(expr.left)) + } + if g.comptime.is_comptime_var(expr.right) { + return g.unwrap_generic(g.comptime.get_comptime_var_type(expr.right)) + } + return default_typ + } + ast.Ident { + return if g.comptime.is_comptime_var(expr) { + g.unwrap_generic(g.comptime.get_comptime_var_type(expr)) + } else { + default_typ + } + } + else { + return default_typ + } + } +} + fn (mut g Gen) resolve_receiver_type(node ast.CallExpr) (ast.Type, &ast.TypeSymbol) { left_type := g.unwrap_generic(node.left_type) mut unwrapped_rec_type := node.receiver_type if g.cur_fn != unsafe { nil } && g.cur_fn.generic_names.len > 0 { // in generic fn unwrapped_rec_type = g.unwrap_generic(node.receiver_type) + unwrapped_rec_type = g.resolve_generic_expr(node.left, unwrapped_rec_type) } else { // in non-generic fn sym := g.table.sym(node.receiver_type) match sym.info { diff --git a/vlib/v/tests/lambda_generic_test.v b/vlib/v/tests/lambda_generic_test.v new file mode 100644 index 00000000000000..1b1378ce2d0367 --- /dev/null +++ b/vlib/v/tests/lambda_generic_test.v @@ -0,0 +1,26 @@ +import arrays + +fn ddd[T](call fn (arg1 T, arg2 T) string, arg1 T, arg2 T) string { + return call(arg1, arg2) +} + +fn abc2[T](arg1 T, arg2 T) string { + return ddd(|x, y| (x + y).str(), arg1, arg2) +} + +fn abc[T](arg T, call fn (a T) string) string { + return call(arg) +} + +fn test_main() { + a := [1, 2, 3, 4] + b := arrays.join_to_string(a, '-', |x| x.str()) + assert b == '1-2-3-4' + assert abc(123, |x| x.str()) == '123' +} + +fn test_generic() { + assert dump(abc2('3', '3')) == '33' + assert dump(abc2(3, 3)) == '6' + assert dump(abc2(3.1, 3.1)) == '6.2' +}