Skip to content

Commit

Permalink
cgen: fix C struct sumtype support (#21129)
Browse files Browse the repository at this point in the history
  • Loading branch information
felipensp authored Mar 30, 2024
1 parent 360886b commit d49fd0f
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 18 deletions.
2 changes: 1 addition & 1 deletion vlib/v/gen/c/auto_eq_methods.v
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down
9 changes: 7 additions & 2 deletions vlib/v/gen/c/auto_str_methods.v
Original file line number Diff line number Diff line change
Expand Up @@ -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}'
}
Expand All @@ -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'
}
Expand Down
42 changes: 28 additions & 14 deletions vlib/v/gen/c/cgen.v
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand All @@ -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 {
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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)}'
Expand All @@ -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
}
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -4751,15 +4765,15 @@ 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')
}
} 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(')')
Expand Down Expand Up @@ -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_] {
Expand Down Expand Up @@ -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
Expand Down
12 changes: 11 additions & 1 deletion vlib/v/tests/c_structs/cstruct.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,14 @@ typedef struct Test2 {

typedef struct Test1 {
Test2 a;
} Test1;
} Test1;

/////

typedef struct Foo {
int a;
} Foo;

typedef struct Bar {
int a;
} Bar;
22 changes: 22 additions & 0 deletions vlib/v/tests/c_structs/cstruct_sumtype_test.v
Original file line number Diff line number Diff line change
@@ -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
}

0 comments on commit d49fd0f

Please sign in to comment.