From 8a39f8c5ce74db08c1b6129cb5e543abaace71b8 Mon Sep 17 00:00:00 2001 From: kbkpbot Date: Thu, 25 Dec 2025 19:05:16 +0800 Subject: [PATCH] cgen: fix fn_var_signature() allow option type (fix #26088) (#26120) --- vlib/v/gen/c/array.v | 8 +++---- vlib/v/gen/c/assign.v | 4 ++-- vlib/v/gen/c/auto_eq_methods.v | 4 ++-- vlib/v/gen/c/consts_and_globals.v | 3 ++- vlib/v/gen/c/fn.v | 16 ++++++------- vlib/v/gen/c/match.v | 4 ++-- vlib/v/gen/c/spawn_and_go.v | 25 ++++++++++++--------- vlib/v/gen/c/utils.v | 10 ++++++--- vlib/v/tests/closure_with_fn_ref_var_test.v | 15 +++++++++++++ 9 files changed, 56 insertions(+), 33 deletions(-) diff --git a/vlib/v/gen/c/array.v b/vlib/v/gen/c/array.v index b0010e3aa..58c01b34a 100644 --- a/vlib/v/gen/c/array.v +++ b/vlib/v/gen/c/array.v @@ -470,8 +470,8 @@ fn (mut g Gen) array_init_with_fields(node ast.ArrayInit, elem_type Type, is_amp } fn (mut g Gen) declare_closure_fn(mut expr ast.AnonFn, var_name string) { - decl_var := g.fn_var_signature(expr.decl.return_type, expr.decl.params.map(it.typ), - var_name, 0) + decl_var := g.fn_var_signature(expr.typ, expr.decl.return_type, expr.decl.params.map(it.typ), + var_name) g.write('${decl_var} = ') g.gen_anon_fn(mut expr) g.writeln(';') @@ -552,8 +552,8 @@ fn (mut g Gen) gen_array_map(node ast.CallExpr) { var_sym := g.table.sym(expr.typ) if var_sym.info is ast.FnType { ret_elem_styp = 'voidptr' - closure_var_decl = g.fn_var_signature(var_sym.info.func.return_type, var_sym.info.func.params.map(it.typ), - tmp_map_expr_result_name, 0) + closure_var_decl = g.fn_var_signature(expr.typ, var_sym.info.func.return_type, + var_sym.info.func.params.map(it.typ), tmp_map_expr_result_name) } } } diff --git a/vlib/v/gen/c/assign.v b/vlib/v/gen/c/assign.v index ea2c68975..b30729b2f 100644 --- a/vlib/v/gen/c/assign.v +++ b/vlib/v/gen/c/assign.v @@ -506,8 +506,8 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) { } // if it's a decl assign (`:=`) or a blank assignment `_ =`/`_ :=` then generate `void (*ident) (args) =` if (is_decl || blank_assign) && left is ast.Ident { - sig := g.fn_var_signature(val.decl.return_type, val.decl.params.map(it.typ), - ident.name, 0) + sig := g.fn_var_signature(val.typ, val.decl.return_type, val.decl.params.map(it.typ), + ident.name) g.write(sig + ' = ') } else { g.is_assign_lhs = true diff --git a/vlib/v/gen/c/auto_eq_methods.v b/vlib/v/gen/c/auto_eq_methods.v index 287234e9d..2afbc442c 100644 --- a/vlib/v/gen/c/auto_eq_methods.v +++ b/vlib/v/gen/c/auto_eq_methods.v @@ -547,8 +547,8 @@ fn (mut g Gen) gen_map_equality_fn(left_type ast.Type) string { initializer := if !(sym.info is ast.Struct && sym.info.is_empty_struct()) { '0' } else { '' } if kind == .function { info := value.sym.info as ast.FnType - sig := g.fn_var_signature(info.func.return_type, info.func.params.map(it.typ), - 'v', 0) + sig := g.fn_var_signature(ast.void_type, info.func.return_type, info.func.params.map(it.typ), + 'v') fn_builder.writeln('\t\t${sig} = *(voidptr*)builtin__map_get(${a}, k, &(voidptr[]){ 0 });') } else { fn_builder.writeln('\t\t${ptr_value_styp} v = *(${ptr_value_styp}*)builtin__map_get(${a}, k, &(${ptr_value_styp}[]){ ${initializer} });') diff --git a/vlib/v/gen/c/consts_and_globals.v b/vlib/v/gen/c/consts_and_globals.v index 2cf5903ba..55a8a2072 100644 --- a/vlib/v/gen/c/consts_and_globals.v +++ b/vlib/v/gen/c/consts_and_globals.v @@ -350,7 +350,8 @@ fn (mut g Gen) const_decl_init_later(mod string, name string, cname string, expr if expr_sym.kind == .function { // allow for: `const xyz = abc`, where `abc` is `fn abc() {}` func := (expr_sym.info as ast.FnType).func - def = g.fn_var_signature(func.return_type, func.params.map(it.typ), cname, 0) + def = g.fn_var_signature(ast.void_type, func.return_type, func.params.map(it.typ), + cname) } init_str := init.str().trim_right('\n') g.global_const_defs[util.no_dots(name)] = GlobalConstDef{ diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index 7ef21441f..3feebd5eb 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -308,8 +308,8 @@ fn (mut g Gen) gen_fn_decl(node &ast.FnDecl, skip bool) { g.definitions.write_string('VV_LOC ${trace_fn_ret_type} ${c_name(trace_fn)}(') if call_fn.is_fn_var { - sig := g.fn_var_signature(call_fn.func.return_type, call_fn.func.params.map(it.typ), - call_fn.name, 0) + sig := g.fn_var_signature(ast.void_type, call_fn.func.return_type, call_fn.func.params.map(it.typ), + call_fn.name) g.write(sig) g.definitions.write_string(sig) } else { @@ -741,8 +741,8 @@ fn (mut g Gen) gen_anon_fn_decl(mut node ast.AnonFn) { for var in node.inherited_vars { var_sym := g.table.sym(var.typ) if var_sym.info is ast.FnType { - mut sig := g.fn_var_signature(var_sym.info.func.return_type, var_sym.info.func.params.map(it.typ), - c_name(var.name), var.typ.nr_muls()) + mut sig := g.fn_var_signature(var.typ, var_sym.info.func.return_type, + var_sym.info.func.params.map(it.typ), c_name(var.name)) g.definitions.writeln('\t' + sig + ';') } else { styp := g.styp(var.typ) @@ -880,8 +880,8 @@ fn (mut g Gen) call_expr(node ast.CallExpr) { if node.left is ast.AnonFn { if node.left.inherited_vars.len > 0 { tmp_anon_fn_var = g.new_tmp_var() - fn_type := g.fn_var_signature(node.left.decl.return_type, node.left.decl.params.map(it.typ), - tmp_anon_fn_var, 0) + fn_type := g.fn_var_signature(ast.void_type, node.left.decl.return_type, node.left.decl.params.map(it.typ), + tmp_anon_fn_var) line := g.go_before_last_stmt().trim_space() g.empty_line = true g.write('${fn_type} = ') @@ -913,8 +913,8 @@ fn (mut g Gen) call_expr(node ast.CallExpr) { left_typ := g.table.value_type(node.left.left_type) tmp_res := g.new_tmp_var() fn_sym := g.table.sym(left_typ).info as ast.FnType - fn_type := g.fn_var_signature(fn_sym.func.return_type, fn_sym.func.params.map(it.typ), - tmp_res, 0) + fn_type := g.fn_var_signature(ast.void_type, fn_sym.func.return_type, fn_sym.func.params.map(it.typ), + tmp_res) old_is_fn_index_call := g.is_fn_index_call g.is_fn_index_call = true diff --git a/vlib/v/gen/c/match.v b/vlib/v/gen/c/match.v index 1806226b3..82a75832f 100644 --- a/vlib/v/gen/c/match.v +++ b/vlib/v/gen/c/match.v @@ -102,8 +102,8 @@ fn (mut g Gen) match_expr(node ast.MatchExpr) { ret_final_sym := g.table.final_sym(node.return_type) if !node.return_type.has_option_or_result() && ret_final_sym.kind == .function { if ret_final_sym.info is ast.FnType { - def := g.fn_var_signature(ret_final_sym.info.func.return_type, ret_final_sym.info.func.params.map(it.typ), - tmp_var, 0) + def := g.fn_var_signature(ast.void_type, ret_final_sym.info.func.return_type, + ret_final_sym.info.func.params.map(it.typ), tmp_var) func_decl = '${def} = &${g.styp(node.return_type)};' } } diff --git a/vlib/v/gen/c/spawn_and_go.v b/vlib/v/gen/c/spawn_and_go.v index 7b422a6e8..c55f68559 100644 --- a/vlib/v/gen/c/spawn_and_go.v +++ b/vlib/v/gen/c/spawn_and_go.v @@ -50,8 +50,8 @@ fn (mut g Gen) spawn_and_go_expr(node ast.SpawnExpr, mode SpawnGoMode) { } } else if mut expr.left is ast.AnonFn { if expr.left.inherited_vars.len > 0 { - fn_var := g.fn_var_signature(expr.left.decl.return_type, expr.left.decl.params.map(it.typ), - tmp_fn, 0) + fn_var := g.fn_var_signature(ast.void_type, expr.left.decl.return_type, expr.left.decl.params.map(it.typ), + tmp_fn) g.write('\t${fn_var} = ') g.gen_anon_fn(mut expr.left) g.writeln(';') @@ -65,8 +65,8 @@ fn (mut g Gen) spawn_and_go_expr(node ast.SpawnExpr, mode SpawnGoMode) { if expr.is_fn_var { fn_sym := g.table.sym(expr.fn_var_type) func := (fn_sym.info as ast.FnType).func - fn_var := g.fn_var_signature(func.return_type, func.params.map(it.typ), tmp_fn, - 0) + fn_var := g.fn_var_signature(ast.void_type, func.return_type, func.params.map(it.typ), + tmp_fn) g.write('\t${fn_var} = ') g.expr(expr.left) g.writeln(';') @@ -185,11 +185,12 @@ fn (mut g Gen) spawn_and_go_expr(node ast.SpawnExpr, mode SpawnGoMode) { if node.call_expr.is_fn_var { fn_sym := g.table.sym(node.call_expr.fn_var_type) info := fn_sym.info as ast.FnType - fn_var = g.fn_var_signature(info.func.return_type, info.func.params.map(it.typ), - 'fn', 0) + fn_var = g.fn_var_signature(ast.void_type, info.func.return_type, info.func.params.map(it.typ), + 'fn') } else if node.call_expr.left is ast.AnonFn { f := node.call_expr.left.decl - fn_var = g.fn_var_signature(f.return_type, f.params.map(it.typ), 'fn', 0) + fn_var = g.fn_var_signature(ast.void_type, f.return_type, f.params.map(it.typ), + 'fn') } else { if node.call_expr.is_method { rec_sym := g.table.sym(g.unwrap_generic(node.call_expr.receiver_type)) @@ -200,7 +201,8 @@ fn (mut g Gen) spawn_and_go_expr(node ast.SpawnExpr, mode SpawnGoMode) { mut arg_types := f.params.map(it.typ) arg_types = arg_types.map(muttable.convert_generic_type(it, f.generic_names, node.call_expr.concrete_types) or { it }) - fn_var = g.fn_var_signature(return_type, arg_types, 'fn', 0) + fn_var = g.fn_var_signature(ast.void_type, return_type, arg_types, + 'fn') } } else { if f := g.table.find_fn(node.call_expr.name) { @@ -223,7 +225,8 @@ fn (mut g Gen) spawn_and_go_expr(node ast.SpawnExpr, mode SpawnGoMode) { } } } - fn_var = g.fn_var_signature(return_type, arg_types, 'fn', 0) + fn_var = g.fn_var_signature(ast.void_type, return_type, arg_types, + 'fn') } } } @@ -238,8 +241,8 @@ fn (mut g Gen) spawn_and_go_expr(node ast.SpawnExpr, mode SpawnGoMode) { for i, arg in expr.args { arg_sym := g.table.sym(arg.typ) if arg_sym.info is ast.FnType { - sig := g.fn_var_signature(arg_sym.info.func.return_type, arg_sym.info.func.params.map(it.typ), - 'arg${i + 1}', arg.typ.nr_muls()) + sig := g.fn_var_signature(arg.typ, arg_sym.info.func.return_type, arg_sym.info.func.params.map(it.typ), + 'arg${i + 1}') g.type_definitions.writeln('\t' + sig + ';') } else { styp := g.styp(arg.typ) diff --git a/vlib/v/gen/c/utils.v b/vlib/v/gen/c/utils.v index 512caec78..17dc8f564 100644 --- a/vlib/v/gen/c/utils.v +++ b/vlib/v/gen/c/utils.v @@ -84,15 +84,19 @@ fn (mut g Gen) unwrap(typ ast.Type) Type { } // generate function variable definition, e.g. `void (*var_name) (int, string)` -fn (mut g Gen) fn_var_signature(return_type ast.Type, arg_types []ast.Type, var_name string, nr_muls int) string { +fn (mut g Gen) fn_var_signature(var_type ast.Type, return_type ast.Type, arg_types []ast.Type, var_name string) string { + if var_type.has_flag(.option) { + return '${g.styp(var_type)} ${c_name(var_name)}' + } ret_styp := g.styp(return_type) + nr_muls := var_type.nr_muls() mut sig := '${ret_styp} (${'*'.repeat(nr_muls + 1)}${c_name(var_name)}) (' for j, arg_typ in arg_types { arg_sym := g.table.sym(arg_typ) if arg_sym.info is ast.FnType { func := arg_sym.info.func - arg_sig := g.fn_var_signature(func.return_type, func.params.map(it.typ), '', - arg_typ.nr_muls()) + arg_sig := g.fn_var_signature(arg_typ, func.return_type, func.params.map(it.typ), + '') sig += arg_sig } else { arg_styp := g.styp(arg_typ) diff --git a/vlib/v/tests/closure_with_fn_ref_var_test.v b/vlib/v/tests/closure_with_fn_ref_var_test.v index 43337bce7..ce0efb796 100644 --- a/vlib/v/tests/closure_with_fn_ref_var_test.v +++ b/vlib/v/tests/closure_with_fn_ref_var_test.v @@ -23,3 +23,18 @@ fn test_closure_with_fn_ref_var() { assert deref() == 1 assert handler() == 1 } + +type Fun = fn () int + +fn test_closure_with_fn_ref_var_option() { + opt := ?Fun(f_a) + + handler := fn [opt] () int { + if g := opt { + return g() + } + return 0 + } + + assert handler() == 1 +} -- 2.39.5