Skip to content

Commit

Permalink
v: allow shared anon struct + fix shared struct field initialization …
Browse files Browse the repository at this point in the history
…with no default value (vlang#23448)
  • Loading branch information
felipensp authored Jan 14, 2025
1 parent ae81095 commit 8f0242e
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 4 deletions.
1 change: 1 addition & 0 deletions vlib/v/ast/types.v
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ pub mut:
is_minify bool
is_anon bool
is_generic bool
is_shared bool
has_option bool // contains any option field
generic_types []Type
concrete_types []Type
Expand Down
3 changes: 3 additions & 0 deletions vlib/v/fmt/struct.v
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,9 @@ fn (mut f Fmt) write_anon_struct_field_decl(field_typ ast.Type, field_anon_decl
info := sym.info as ast.Struct
if info.is_anon {
f.indent++
if info.is_shared {
f.write('shared ')
}
f.struct_decl(field_anon_decl, true)
f.indent--
return true
Expand Down
8 changes: 6 additions & 2 deletions vlib/v/gen/c/auto_str_methods.v
Original file line number Diff line number Diff line change
Expand Up @@ -1008,7 +1008,11 @@ fn (mut g Gen) gen_str_for_struct(info ast.Struct, lang ast.Language, styp strin
} else {
''
}
base_fmt := g.type_to_fmt(g.unwrap_generic(field.typ))
mut base_typ := g.unwrap_generic(field.typ)
if base_typ.has_flag(.shared_f) {
base_typ = base_typ.clear_flag(.shared_f).deref()
}
base_fmt := g.type_to_fmt(base_typ)
is_opt_field := field.typ.has_flag(.option)

// manage prefix and quote symbol for the filed
Expand Down Expand Up @@ -1194,7 +1198,7 @@ fn struct_auto_str_func(sym &ast.TypeSymbol, lang ast.Language, _field_type ast.
if !field_type.is_ptr() && field_type.has_option_or_result() {
method_str = '(*(${sym.name}*)it${op}${final_field_name}.data)'
} else {
method_str = 'it${op}${final_field_name}'
method_str = 'it${op}${final_field_name}${sufix}'
}
if sym.kind == .bool {
return '${method_str} ? _SLIT("true") : _SLIT("false")', false
Expand Down
21 changes: 20 additions & 1 deletion vlib/v/gen/c/struct.v
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,14 @@ fn (mut g Gen) get_embed_field_name(field_type ast.Type, field_name string) stri
return s
}

fn (mut g Gen) init_shared_field(field ast.StructField) {
field_typ := field.typ.deref()
shared_styp := g.styp(field_typ)
g.write('(${shared_styp}*)__dup${shared_styp}(&(${shared_styp}){.mtx= {0}, .val=')
g.write(g.type_default(field_typ.clear_flag(.shared_f)))
g.write('}, sizeof(${shared_styp}))')
}

fn (mut g Gen) zero_struct_field(field ast.StructField) bool {
old_inside_cast_in_heap := g.inside_cast_in_heap
g.inside_cast_in_heap = 0
Expand All @@ -428,6 +436,11 @@ fn (mut g Gen) zero_struct_field(field ast.StructField) bool {
return false
} else if !field.has_default_expr {
mut has_option_field := false
if sym.info.is_shared || field.typ.has_flag(.shared_f) {
g.write('.${field_name} = ')
g.init_shared_field(field)
return true
}
for fd in sym.info.fields {
if fd.typ.has_flag(.option) {
has_option_field = true
Expand Down Expand Up @@ -520,6 +533,8 @@ fn (mut g Gen) zero_struct_field(field ast.StructField) bool {
}
}
g.write('}')
} else if field.typ.has_flag(.shared_f) {
g.init_shared_field(field)
} else {
g.write(g.type_default(field.typ))
}
Expand Down Expand Up @@ -570,7 +585,11 @@ fn (mut g Gen) struct_decl(s ast.Struct, name string, is_anon bool) {
}
}
if is_anon {
g.type_definitions.write_string('\t${name} ')
if s.is_shared {
g.type_definitions.write_string('\t__shared__${name}* ')
} else {
g.type_definitions.write_string('\t${name} ')
}
return
} else if s.is_union {
if g.is_cc_msvc && aligned_attr != '' {
Expand Down
14 changes: 13 additions & 1 deletion vlib/v/parser/struct.v
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,15 @@ fn (mut p Parser) struct_decl(is_anon bool) ast.StructDecl {
attrs := p.attrs
start_pos := p.tok.pos()
mut is_pub := p.tok.kind == .key_pub
mut is_shared := p.tok.kind == .key_shared
if is_pub {
p.next()
}
if is_anon {
if is_shared {
p.register_auto_import('sync')
p.next()
}
is_pub = true
}
is_union := p.tok.kind == .key_union
Expand Down Expand Up @@ -236,12 +241,18 @@ fn (mut p Parser) struct_decl(is_anon bool) ast.StructDecl {
// struct field
field_name = p.check_name()
p.inside_struct_field_decl = true
if p.tok.kind == .key_struct {
if p.tok.kind == .key_struct
|| (p.tok.kind == .key_shared && p.peek_tok.kind == .key_struct) {
// Anon structs
field_is_shared := p.tok.kind == .key_shared
p.anon_struct_decl = p.struct_decl(true)
p.anon_struct_decl.language = language
// Find the registered anon struct type, it was registered above in `p.struct_decl()`
typ = p.table.find_type_idx(p.anon_struct_decl.name)
if field_is_shared {
typ = typ.set_flag(.shared_f)
typ = typ.set_nr_muls(1)
}
} else {
start_type_pos := p.tok.pos()
typ = p.parse_type()
Expand Down Expand Up @@ -379,6 +390,7 @@ fn (mut p Parser) struct_decl(is_anon bool) ast.StructDecl {
generic_types: generic_types
attrs: attrs
is_anon: is_anon
is_shared: is_shared
has_option: has_option
}
is_pub: is_pub
Expand Down
26 changes: 26 additions & 0 deletions vlib/v/tests/structs/struct_field_shared_test.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
struct Foo {
bar shared struct {
mut:
foo int
bar int
}
baz shared int
}

fn test_main() {
assert Foo{}.str() == 'Foo{
bar: struct {
foo: 0
bar: 0
}
baz: 0
}'
mut t := Foo{}
lock t.bar {
t.bar.foo = 1
t.bar.bar = 2
}
rlock t.bar {
assert t.bar.foo + t.bar.bar == 3
}
}

0 comments on commit 8f0242e

Please sign in to comment.