From 5777a5405e09599d8de6f263c9f993780f5fcada Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Thu, 30 Apr 2026 02:53:33 +0300 Subject: [PATCH] cgen, checker: generics fix (fixes #27032) --- vlib/v/checker/fn.v | 2 +- vlib/v/gen/c/fn.v | 22 +++++++++ .../v/generics/new_generics_regression_test.v | 5 +- ...eric_method_fn_field_result_recheck_test.v | 48 +++++++++++++++++++ 4 files changed, 74 insertions(+), 3 deletions(-) create mode 100644 vlib/v/tests/generics/generic_method_fn_field_result_recheck_test.v diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index cd9456a2e..295631f40 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -2204,7 +2204,7 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast. } if node.kind == .free && func.mod == 'builtin' && args_len == 1 && c.table.cur_fn != unsafe { nil } && c.table.cur_fn.is_method && !c.is_builtin_mod - && c.table.cur_fn.name.all_after_last('.') != 'free' && !c.inside_recheck { + && !c.inside_recheck { if node.args[0].expr is ast.Ident { if node.args[0].expr.name == c.table.cur_fn.receiver.name { receiver_sym := c.table.sym(c.table.cur_fn.receiver.typ) diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index 3b1e24443..900d5a56c 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -2867,6 +2867,28 @@ fn (mut g Gen) resolve_return_type(node ast.CallExpr) ast.Type { return_type.clear_option_and_result() } } + if node.is_field { + selector := ast.SelectorExpr{ + expr: node.left + expr_type: left_type + field_name: node.name + } + fn_typ := g.resolved_selector_field_type(selector, left_type) + if fn_typ != 0 { + fn_sym := g.table.final_sym(fn_typ.clear_option_and_result()) + if fn_sym.info is ast.FnType { + return_type := + g.unwrap_generic(g.recheck_concrete_type(fn_sym.info.func.return_type)) + if return_type != 0 { + return if node.or_block.kind == .absent { + return_type + } else { + return_type.clear_option_and_result() + } + } + } + } + } func := left_sym.find_method_with_generic_parent(node.name) or { g.table.find_method(left_sym, node.name) or { return ast.void_type } } diff --git a/vlib/v/generics/new_generics_regression_test.v b/vlib/v/generics/new_generics_regression_test.v index 4eb0b667d..501c9f330 100644 --- a/vlib/v/generics/new_generics_regression_test.v +++ b/vlib/v/generics/new_generics_regression_test.v @@ -117,9 +117,9 @@ fn run_new_generic_solver_tests(root_label string, test_cmd string, expected_sum println('') } -const expected_summsvc_generics = 'Summary for all V _test.v files: 110 failed, 182 passed, 292 total.' +const expected_summsvc_generics = 'Summary for all V _test.v files: 111 failed, 182 passed, 293 total.' // The exact failure count varies slightly across compilers. -const expected_summary_generics = 'Summary for all V _test.v files: 106 failed, 185 passed, 291 total.' +const expected_summary_generics = 'Summary for all V _test.v files: 107 failed, 185 passed, 292 total.' const expected_summsvc_vec = 'Summary for all V _test.v files: 3 failed, 3 total.' const expected_summary_vec = 'Summary for all V _test.v files: 3 failed, 3 total.' const expected_summsvc_flag = 'Summary for all V _test.v files: 21 passed, 21 total.' @@ -154,6 +154,7 @@ const failing_tests = [ 'vlib/v/tests/generics/generic_map_alias_test.v', 'vlib/v/tests/generics/generic_match_expr_test.v', 'vlib/v/tests/generics/generic_match_generic_interface_type_test.v', + 'vlib/v/tests/generics/generic_method_fn_field_result_recheck_test.v', 'vlib/v/tests/generics/generic_method_with_variadic_generic_args_test.v', 'vlib/v/tests/generics/generic_mut_pointer_param_test.v', 'vlib/v/tests/generics/generic_operator_overload_test.v', diff --git a/vlib/v/tests/generics/generic_method_fn_field_result_recheck_test.v b/vlib/v/tests/generics/generic_method_fn_field_result_recheck_test.v new file mode 100644 index 000000000..3a714b3a4 --- /dev/null +++ b/vlib/v/tests/generics/generic_method_fn_field_result_recheck_test.v @@ -0,0 +1,48 @@ +// Reproducer for issue 27032: a generic method forwarding to a generic function +// field used to generate stale Result C types after monomorphization. + +struct Pair[A, B] { +pub: + first A + second B +} + +struct Box[T] { + run fn (int) !T = unsafe { nil } +} + +fn (b Box[T]) call(x int) !T { + return b.run(x)! +} + +fn combine[A, B](a Box[A], b Box[B]) Box[Pair[A, B]] { + return Box[Pair[A, B]]{ + run: fn [a, b] [A, B](x int) !Pair[A, B] { + first := a.call(x)! + second := b.call(x)! + return Pair[A, B]{ + first: first + second: second + } + } + } +} + +fn int_box() Box[int] { + return Box[int]{ + run: fn (x int) !int { + return x + 1 + } + } +} + +fn use[T](b Box[T]) !T { + return b.call(0)! +} + +fn test_generic_method_fn_field_result_recheck() ! { + b := combine[int, int](int_box(), int_box()) + v := use[Pair[int, int]](b)! + assert v.first == 1 + assert v.second == 1 +} -- 2.39.5