diff --git a/vlib/v/gen/c/assign.v b/vlib/v/gen/c/assign.v index b2df3b9daf5d7c..4d3fda156d47a3 100644 --- a/vlib/v/gen/c/assign.v +++ b/vlib/v/gen/c/assign.v @@ -1015,7 +1015,8 @@ fn (mut g Gen) gen_cross_var_assign(node &ast.AssignStmt) { } } if left_sym.kind == .function { - g.write_fn_ptr_decl(left_sym.info as ast.FnType, '_var_${left.pos.pos}') + g.write_fn_ptr_decl(left_sym.info as ast.FnType, '_var_${left.pos.pos}', + true) g.writeln(' = ${anon_ctx}${c_name(left.name)};') } else if left_is_auto_deref_var { styp := g.styp(left_typ).trim('*') @@ -1043,7 +1044,8 @@ fn (mut g Gen) gen_cross_var_assign(node &ast.AssignStmt) { if elem_typ.kind == .function { left_typ := node.left_types[i] left_sym := g.table.sym(left_typ) - g.write_fn_ptr_decl(left_sym.info as ast.FnType, '_var_${left.pos.pos}') + g.write_fn_ptr_decl(left_sym.info as ast.FnType, '_var_${left.pos.pos}', + true) g.write(' = *(voidptr*)array_get(') } else { styp := g.styp(info.elem_type) @@ -1068,7 +1070,8 @@ fn (mut g Gen) gen_cross_var_assign(node &ast.AssignStmt) { if elem_typ.kind == .function { left_typ := node.left_types[i] left_sym := g.table.sym(left_typ) - g.write_fn_ptr_decl(left_sym.info as ast.FnType, '_var_${left.pos.pos}') + g.write_fn_ptr_decl(left_sym.info as ast.FnType, '_var_${left.pos.pos}', + true) g.write(' = *(voidptr*)') } else { styp := g.styp(info.elem_type) @@ -1095,7 +1098,8 @@ fn (mut g Gen) gen_cross_var_assign(node &ast.AssignStmt) { if val_typ.kind == .function { left_type := node.left_types[i] left_sym := g.table.sym(left_type) - g.write_fn_ptr_decl(left_sym.info as ast.FnType, '_var_${left.pos.pos}') + g.write_fn_ptr_decl(left_sym.info as ast.FnType, '_var_${left.pos.pos}', + true) g.write(' = *(voidptr*)map_get(') } else { g.write('${styp} _var_${left.pos.pos} = *(${styp}*)map_get(') diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 909660238b5297..65828c3b767d95 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -1654,7 +1654,7 @@ pub fn (mut g Gen) write_typedef_types() { if elem_sym.info is ast.FnType { pos := g.out.len // pos2:=g.out_parallel[g.out_idx].len - g.write_fn_ptr_decl(&elem_sym.info, '') + g.write_fn_ptr_decl(&elem_sym.info, '', true) fixed = g.out.cut_to(pos) // g.out_parallel[g.out_idx].cut_to(pos2) mut def_str := 'typedef ${fixed};' @@ -2172,13 +2172,14 @@ fn (mut g Gen) expr_with_tmp_var(expr ast.Expr, expr_typ ast.Type, ret_typ ast.T stmt_str := g.go_before_last_stmt().trim_space() mut styp := g.base_type(ret_typ) g.empty_line = true + final_expr_sym := g.table.final_sym(expr_typ) - if g.table.sym(expr_typ).kind == .none { + if final_expr_sym.kind == .none { g.write('${g.styp(ret_typ)} ${tmp_var} = ') g.gen_option_error(ret_typ, expr) g.writeln(';') } else if expr is ast.Ident && expr_typ == ast.error_type { - g.writeln('${g.styp(ret_typ)} ${tmp_var} = {.state=2, .err = ${expr.name}};') + g.writeln('${g.styp(ret_typ)} ${tmp_var} = {.state=2, .err=${expr.name}};') } else { mut simple_assign := false if ret_typ.has_flag(.generic) { @@ -2225,6 +2226,14 @@ fn (mut g Gen) expr_with_tmp_var(expr ast.Expr, expr_typ ast.Type, ret_typ ast.T g.write('_option_none(&(${styp}[]) { ') } else { g.write('_option_ok(&(${styp}[]) { ') + if final_expr_sym.info is ast.FnType { + final_ret_sym := g.table.final_sym(ret_typ) + if final_ret_sym.info is ast.FnType { + g.write('(') + g.write_fn_ptr_decl(&final_ret_sym.info, '', false) + g.write(')') + } + } } if ret_typ.nr_muls() > expr_typ.nr_muls() { g.write('&'.repeat(ret_typ.nr_muls() - expr_typ.nr_muls())) @@ -3192,13 +3201,16 @@ fn cnewlines(s string) string { return s.replace('\n', r'\n') } -fn (mut g Gen) write_fn_ptr_decl(func &ast.FnType, ptr_name string) { +fn (mut g Gen) write_fn_ptr_decl(func &ast.FnType, ptr_name string, with_argname bool) { ret_styp := g.styp(func.func.return_type) g.write('${ret_styp} (*${ptr_name}) (') arg_len := func.func.params.len for i, arg in func.func.params { arg_styp := g.styp(arg.typ) - g.write('${arg_styp} ${arg.name}') + g.write(arg_styp) + if with_argname { + g.write(' ${arg.name}') + } if i < arg_len - 1 { g.write(', ') } @@ -6625,7 +6637,7 @@ fn (mut g Gen) write_types(symbols []&ast.TypeSymbol) { if len > 0 { if elem_sym.info is ast.FnType { pos := g.out.len - g.write_fn_ptr_decl(&elem_sym.info, '') + g.write_fn_ptr_decl(&elem_sym.info, '', true) fixed_elem_name = g.out.cut_to(pos) mut def_str := 'typedef ${fixed_elem_name};' def_str = def_str.replace_once('(*)', '(*${styp}[${len}])') diff --git a/vlib/v/gen/c/dumpexpr.v b/vlib/v/gen/c/dumpexpr.v index 246a07388280af..def2a38a160dd3 100644 --- a/vlib/v/gen/c/dumpexpr.v +++ b/vlib/v/gen/c/dumpexpr.v @@ -133,7 +133,7 @@ fn (mut g Gen) dump_expr_definitions() { fninfo := dump_sym.info as ast.FnType str_dumparg_type = 'DumpFNType_${name}' tdef_pos := g.out.len - g.write_fn_ptr_decl(&fninfo, str_dumparg_type) + g.write_fn_ptr_decl(&fninfo, str_dumparg_type, true) str_tdef := g.out.after(tdef_pos) g.go_back(str_tdef.len) dump_typedefs['typedef ${str_tdef};'] = true diff --git a/vlib/v/gen/c/for.v b/vlib/v/gen/c/for.v index 944a3a76c84faa..b93d58fa9d6fe2 100644 --- a/vlib/v/gen/c/for.v +++ b/vlib/v/gen/c/for.v @@ -260,7 +260,8 @@ fn (mut g Gen) for_in_stmt(node_ ast.ForInStmt) { if node.val_var != '_' { if val_sym.kind == .function { g.write('\t') - g.write_fn_ptr_decl(val_sym.info as ast.FnType, c_name(node.val_var)) + g.write_fn_ptr_decl(val_sym.info as ast.FnType, c_name(node.val_var), + true) g.writeln(' = ((voidptr*)${cond_var}${op_field}data)[${i}];') } else if val_sym.kind == .array_fixed && !node.val_is_mut { right := '((${styp}*)${cond_var}${op_field}data)[${i}]' @@ -322,7 +323,8 @@ fn (mut g Gen) for_in_stmt(node_ ast.ForInStmt) { is_fixed_array := val_sym.kind == .array_fixed && !node.val_is_mut if val_sym.kind == .function { g.write('\t') - g.write_fn_ptr_decl(val_sym.info as ast.FnType, c_name(node.val_var)) + g.write_fn_ptr_decl(val_sym.info as ast.FnType, c_name(node.val_var), + true) } else if is_fixed_array { styp := g.styp(node.val_type) g.writeln('\t${styp} ${c_name(node.val_var)};') @@ -388,7 +390,8 @@ fn (mut g Gen) for_in_stmt(node_ ast.ForInStmt) { if node.val_var != '_' { val_sym := g.table.sym(node.val_type) if val_sym.kind == .function { - g.write_fn_ptr_decl(val_sym.info as ast.FnType, c_name(node.val_var)) + g.write_fn_ptr_decl(val_sym.info as ast.FnType, c_name(node.val_var), + true) g.write(' = (*(voidptr*)') g.writeln('DenseArray_value(&${cond_var}${dot_or_ptr}key_values, ${idx}));') } else if val_sym.kind == .array_fixed && !node.val_is_mut { diff --git a/vlib/v/gen/c/index.v b/vlib/v/gen/c/index.v index 8a1d59fac3782e..3472f1366f15a0 100644 --- a/vlib/v/gen/c/index.v +++ b/vlib/v/gen/c/index.v @@ -261,7 +261,7 @@ fn (mut g Gen) index_of_array(node ast.IndexExpr, sym ast.TypeSymbol) { if is_fn_index_call { if elem_sym.info is ast.FnType { g.write('((') - g.write_fn_ptr_decl(&elem_sym.info, '') + g.write_fn_ptr_decl(&elem_sym.info, '', true) if is_direct_array_access { g.write(')((${elem_type_str}*)') } else { @@ -484,7 +484,7 @@ fn (mut g Gen) index_of_map(node ast.IndexExpr, sym ast.TypeSymbol) { if g.is_fn_index_call { if val_sym.info is ast.FnType { g.write('((') - g.write_fn_ptr_decl(&val_sym.info, '') + g.write_fn_ptr_decl(&val_sym.info, '', true) g.write(')(*(voidptr*)map_get(') is_fn_last_index_call = true g.is_fn_index_call = false diff --git a/vlib/v/tests/options/option_fn_voidptr_test.v b/vlib/v/tests/options/option_fn_voidptr_test.v new file mode 100644 index 00000000000000..34f7aa7de56cb6 --- /dev/null +++ b/vlib/v/tests/options/option_fn_voidptr_test.v @@ -0,0 +1,18 @@ +struct Foo { +mut: + func ?fn (voidptr) = unsafe { nil } +} + +fn callback(foo &Foo) { +} + +fn test_main() { + t := Foo{ + func: callback + } + assert t.func? == callback + + mut a := Foo{} + a.func = callback + assert a.func? == callback +}