From 1f10a65515b2f821f8ee05efeadf3c76c209e2f7 Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Sun, 16 Mar 2025 08:09:56 -0300 Subject: [PATCH] cgen: fix codegen for generic structinit and generic array return (fix #23916) (#23943) --- vlib/v/gen/c/fn.v | 11 +++++++ .../v/tests/generics/generic_array_ret_test.v | 32 +++++++++++++++++++ vlib/v/type_resolver/generic_resolver.v | 12 +++++++ 3 files changed, 55 insertions(+) create mode 100644 vlib/v/tests/generics/generic_array_ret_test.v diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index 6ab0578dff..a2d0c9d57a 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -991,6 +991,17 @@ fn (mut g Gen) call_expr(node ast.CallExpr) { if unaliased_type.has_option_or_result() { ret_typ = unaliased_type } + } else if node.return_type_generic != 0 && node.raw_concrete_types.len == 0 { + unwrapped_ret_typ := g.unwrap_generic(node.return_type_generic) + if !unwrapped_ret_typ.has_flag(.generic) { + ret_sym := g.table.sym(unwrapped_ret_typ) + if ret_sym.info is ast.Array && g.table.sym(node.return_type_generic).kind == .array { + // Make []T returns T type when array was supplied to T + if g.table.type_to_str(node.return_type_generic).count('[]') < g.table.type_to_str(unwrapped_ret_typ).count('[]') { + ret_typ = g.unwrap_generic(ret_sym.info.elem_type).derive(unwrapped_ret_typ) + } + } + } } mut styp := g.styp(ret_typ) if gen_or && !is_gen_or_and_assign_rhs { diff --git a/vlib/v/tests/generics/generic_array_ret_test.v b/vlib/v/tests/generics/generic_array_ret_test.v new file mode 100644 index 0000000000..185e52d1d8 --- /dev/null +++ b/vlib/v/tests/generics/generic_array_ret_test.v @@ -0,0 +1,32 @@ +module main + +fn decode_primitive[T]() !T { + $if T is int { + return T(1) + } $else $if T is u8 { + return T(10) + } $else $if T is u16 { + return T(100) + } + return error('decode_primitive: not found') +} + +fn decode_array[T](_ []T) ![]T { + mut arr := []T{} + arr << decode_primitive[T]()! + return arr +} + +fn decode[T]() !T { + $if T is $array { + a := decode_array(T{})! + return a + } + return error('decode: not found') +} + +fn test_main() { + assert decode[[]int]()! == [1] + assert decode[[]u8]()! == [u8(10)] + assert decode[[]u16]()! == [u16(100)] +} diff --git a/vlib/v/type_resolver/generic_resolver.v b/vlib/v/type_resolver/generic_resolver.v index aab11a4e09..ed5b85e09c 100644 --- a/vlib/v/type_resolver/generic_resolver.v +++ b/vlib/v/type_resolver/generic_resolver.v @@ -316,6 +316,18 @@ pub fn (mut t TypeResolver) resolve_args(cur_fn &ast.FnDecl, func &ast.Fn, mut n ctyp = cparam_type_sym.info.elem_type } comptime_args[k] = ctyp + } else if mut call_arg.expr is ast.StructInit && call_arg.expr.typ.has_flag(.generic) { + mut ctyp := t.resolver.unwrap_generic(call_arg.expr.typ) + param_typ_sym := t.table.sym(param_typ) + cparam_type_sym := t.table.sym(ctyp) + if param_typ_sym.kind == .array && cparam_type_sym.info is ast.Array { + comptime_args[k] = cparam_type_sym.info.elem_type + } else if param_typ_sym.kind == .map && cparam_type_sym.info is ast.Map { + comptime_args[k] = cparam_type_sym.info.key_type + comptime_args[k + 1] = cparam_type_sym.info.value_type + } else { + comptime_args[k] = ctyp + } } } return comptime_args