From d49fd0f4a77f31e62a4a615af50872263e81c3d6 Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Sat, 30 Mar 2024 12:29:12 -0300 Subject: [PATCH] cgen: fix C struct sumtype support (#21129) --- vlib/v/gen/c/auto_eq_methods.v | 2 +- vlib/v/gen/c/auto_str_methods.v | 9 +++- vlib/v/gen/c/cgen.v | 42 ++++++++++++------- vlib/v/tests/c_structs/cstruct.h | 12 +++++- vlib/v/tests/c_structs/cstruct_sumtype_test.v | 22 ++++++++++ 5 files changed, 69 insertions(+), 18 deletions(-) create mode 100644 vlib/v/tests/c_structs/cstruct_sumtype_test.v diff --git a/vlib/v/gen/c/auto_eq_methods.v b/vlib/v/gen/c/auto_eq_methods.v index 0f0e1bce0d2e20..3670b990d32a2e 100644 --- a/vlib/v/gen/c/auto_eq_methods.v +++ b/vlib/v/gen/c/auto_eq_methods.v @@ -72,7 +72,7 @@ fn (mut g Gen) gen_sumtype_equality_fn(left_type ast.Type) string { for typ in info.variants { variant := g.unwrap(typ) fn_builder.writeln('\tif (${left_typ} == ${int(variant.typ)}) {') - name := '_${g.get_sumtype_variant_name(variant.typ, variant.sym.cname)}' + name := '_${g.get_sumtype_variant_name(variant.typ, variant.sym)}' left_arg := g.read_field(left_type, name, 'a') right_arg := g.read_field(left_type, name, 'b') diff --git a/vlib/v/gen/c/auto_str_methods.v b/vlib/v/gen/c/auto_str_methods.v index 6d02a583048309..9bf0fd42da68bc 100644 --- a/vlib/v/gen/c/auto_str_methods.v +++ b/vlib/v/gen/c/auto_str_methods.v @@ -440,8 +440,13 @@ fn (mut g Gen) gen_str_for_union_sum_type(info ast.SumType, styp string, typ_str typ_name := g.typ(typ) mut func_name := g.get_str_fn(typ) sym := g.table.sym(typ) + is_c_struct := sym.is_c_struct() sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info() - deref := if sym_has_str_method && str_method_expects_ptr { ' ' } else { '*' } + deref := if is_c_struct || (sym_has_str_method && str_method_expects_ptr) { + ' ' + } else { + '*' + } if should_use_indent_func(sym.kind) && !sym_has_str_method { func_name = 'indent_${func_name}' } @@ -460,7 +465,7 @@ fn (mut g Gen) gen_str_for_union_sum_type(info ast.SumType, styp string, typ_str fn_builder.write_string('\t\tcase ${int(typ)}: return ${res};\n') } else { mut val := '${func_name}(${deref}(${typ_name}*)x._${g.get_sumtype_variant_name(typ, - sym.cname)}' + sym)}' if should_use_indent_func(sym.kind) && !sym_has_str_method { val += ', indent_count' } diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index d53c107bf60d7f..7760c061adfed6 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -915,10 +915,22 @@ pub fn (mut g Gen) finish() { } } +// get_sumtype_variant_type_name returns the variant type name according to its type +@[inline] +pub fn (mut g Gen) get_sumtype_variant_type_name(typ ast.Type, sym ast.TypeSymbol) string { + return if typ.has_flag(.option) { + '_option_${sym.cname}' + } else if sym.is_c_struct() { + g.cc_type(typ, true) + } else { + sym.cname + } +} + // get_sumtype_variant_name returns the variant name according to its type @[inline] -pub fn (mut g Gen) get_sumtype_variant_name(typ ast.Type, name string) string { - return if typ.has_flag(.option) { '_option_${name}' } else { name } +pub fn (mut g Gen) get_sumtype_variant_name(typ ast.Type, sym ast.TypeSymbol) string { + return if typ.has_flag(.option) { '_option_${sym.cname}' } else { sym.cname } } pub fn (mut g Gen) write_typeof_functions() { @@ -937,7 +949,7 @@ pub fn (mut g Gen) write_typeof_functions() { for v in sum_info.variants { subtype := g.table.sym(v) g.writeln('\tif( sidx == _v_type_idx_${g.get_sumtype_variant_name(v, - subtype.cname)}() ) return "${util.strip_main_name(subtype.name)}";') + subtype)}() ) return "${util.strip_main_name(subtype.name)}";') } g.writeln('\treturn "unknown ${util.strip_main_name(sym.name)}";') } else { @@ -2317,10 +2329,10 @@ fn (mut g Gen) get_sumtype_casting_fn(got_ ast.Type, exp_ ast.Type) string { cname := if exp == ast.int_type_idx { ast.int_type_name } else { - g.get_sumtype_variant_name(exp_, exp_sym.cname) + g.get_sumtype_variant_name(exp_, exp_sym) } // fn_name := '${got_sym.cname}_to_sumtype_${exp_sym.cname}' - fn_name := '${g.get_sumtype_variant_name(got_, got_sym.cname)}_to_sumtype_${cname}/*KEK*/' + fn_name := '${g.get_sumtype_variant_name(got_, got_sym)}_to_sumtype_${cname}/*KEK*/' if got == exp || g.sumtype_definitions[i] { return fn_name } @@ -2349,10 +2361,11 @@ fn (mut g Gen) get_sumtype_casting_fn(got_ ast.Type, exp_ ast.Type) string { fn (mut g Gen) write_sumtype_casting_fn(fun SumtypeCastingFn) { got, exp := fun.got, fun.exp got_sym, exp_sym := g.table.sym(got), g.table.sym(exp) - mut got_cname, exp_cname := g.get_sumtype_variant_name(got, got_sym.cname), exp_sym.cname + mut got_cname, exp_cname := g.get_sumtype_variant_type_name(got, got_sym), exp_sym.cname mut type_idx := g.type_sidx(got) mut sb := strings.new_builder(128) mut is_anon_fn := false + mut variant_name := g.get_sumtype_variant_name(got, got_sym) if got_sym.info is ast.FnType { got_name := 'fn ${g.table.fn_type_source_signature(got_sym.info.func)}' got_cname = 'anon_fn_${g.table.fn_type_signature(got_sym.info.func)}' @@ -2362,8 +2375,9 @@ fn (mut g Gen) write_sumtype_casting_fn(fun SumtypeCastingFn) { variant_sym := g.table.sym(variant) if variant_sym.info is ast.FnType { if g.table.fn_type_source_signature(variant_sym.info.func) == g.table.fn_type_source_signature(got_sym.info.func) { - got_cname = variant_sym.cname - type_idx = variant.idx().str() + variant_name = g.get_sumtype_variant_name(variant, variant_sym) + got_cname = g.get_sumtype_variant_type_name(variant, variant_sym) + type_idx = int(variant).str() break } } @@ -2393,7 +2407,7 @@ fn (mut g Gen) write_sumtype_casting_fn(fun SumtypeCastingFn) { // if the variable is not used, the C compiler will optimize it away sb.writeln('\t${embed_cname}* ${embed_name}_ptr = memdup(${accessor}, sizeof(${embed_cname}));') } - sb.write_string('\treturn (${exp_cname}){ ._${got_cname} = ptr, ._typ = ${type_idx}') + sb.write_string('\treturn (${exp_cname}){ ._${variant_name} = ptr, ._typ = ${type_idx}') for field in (exp_sym.info as ast.SumType).fields { mut ptr := 'ptr' mut type_cname := got_cname @@ -4751,7 +4765,7 @@ fn (mut g Gen) ident(node ast.Ident) { if node.obj.ct_type_var == .smartcast { ctyp := g.unwrap_generic(g.comptime.get_comptime_var_type(node)) cur_variant_sym := g.table.sym(ctyp) - variant_name := g.get_sumtype_variant_name(ctyp, cur_variant_sym.cname) + variant_name := g.get_sumtype_variant_name(ctyp, cur_variant_sym) g.write('._${variant_name}') if node.obj.is_unwrapped { g.write('.data') @@ -4759,7 +4773,7 @@ fn (mut g Gen) ident(node ast.Ident) { } else if obj_sym.kind == .sum_type { variant_typ := g.unwrap_generic(node.obj.smartcasts.last()) cast_sym := g.table.sym(g.unwrap_generic(node.obj.smartcasts.last())) - variant_name := g.get_sumtype_variant_name(variant_typ, cast_sym.cname) + variant_name := g.get_sumtype_variant_name(variant_typ, cast_sym) g.write('._${variant_name}') } g.write(')') @@ -4841,11 +4855,11 @@ fn (mut g Gen) ident(node ast.Ident) { if node.obj.is_unwrapped { ctyp = ctyp.set_flag(.option) g.write('${dot}_${g.get_sumtype_variant_name(ctyp, - cur_variant_sym.cname)}') + cur_variant_sym)}') g.write(').data') } else { g.write('${dot}_${g.get_sumtype_variant_name(ctyp, - cur_variant_sym.cname)}') + cur_variant_sym)}') } } else if !is_option_unwrap && obj_sym.kind in [.sum_type, .interface_] { @@ -6524,7 +6538,7 @@ fn (mut g Gen) write_types(symbols []&ast.TypeSymbol) { for variant in sym.info.variants { variant_sym := g.table.sym(variant) mut var := if variant.has_flag(.option) { variant } else { variant.ref() } - variant_name := g.get_sumtype_variant_name(variant, variant_sym.cname) + variant_name := g.get_sumtype_variant_name(variant, variant_sym) if variant_sym.info is ast.FnType { if variant_sym.info.is_anon { var = variant diff --git a/vlib/v/tests/c_structs/cstruct.h b/vlib/v/tests/c_structs/cstruct.h index 7f7d1c6b027b94..10cca97a4d75fb 100644 --- a/vlib/v/tests/c_structs/cstruct.h +++ b/vlib/v/tests/c_structs/cstruct.h @@ -9,4 +9,14 @@ typedef struct Test2 { typedef struct Test1 { Test2 a; -} Test1; \ No newline at end of file +} Test1; + +///// + +typedef struct Foo { + int a; +} Foo; + +typedef struct Bar { + int a; +} Bar; diff --git a/vlib/v/tests/c_structs/cstruct_sumtype_test.v b/vlib/v/tests/c_structs/cstruct_sumtype_test.v new file mode 100644 index 00000000000000..aacdc16a2e2b51 --- /dev/null +++ b/vlib/v/tests/c_structs/cstruct_sumtype_test.v @@ -0,0 +1,22 @@ +#include "@VMODROOT/cstruct.h" + +const the_string = 'the string' + +@[typedef] +struct C.Foo { + a int +} + +struct C.Bar { + a int +} + +type Baz = C.Bar | C.Foo + +fn test_cstruct() { + a := Baz(C.Foo{ + a: 1000 + }) + dump(a) + assert (a as C.Foo).a == 1000 +}