diff --git a/vlib/v/ast/types.v b/vlib/v/ast/types.v index 8d989b79a8d134..d9df49b3adccd6 100644 --- a/vlib/v/ast/types.v +++ b/vlib/v/ast/types.v @@ -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 diff --git a/vlib/v/fmt/struct.v b/vlib/v/fmt/struct.v index 19483f8e1deb62..db26de4cd4e8d6 100644 --- a/vlib/v/fmt/struct.v +++ b/vlib/v/fmt/struct.v @@ -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 diff --git a/vlib/v/gen/c/auto_str_methods.v b/vlib/v/gen/c/auto_str_methods.v index d3cbbf8262280c..8a25ce27e6a123 100644 --- a/vlib/v/gen/c/auto_str_methods.v +++ b/vlib/v/gen/c/auto_str_methods.v @@ -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 @@ -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 diff --git a/vlib/v/gen/c/struct.v b/vlib/v/gen/c/struct.v index 51d26023576ffd..f1985463bb84dc 100644 --- a/vlib/v/gen/c/struct.v +++ b/vlib/v/gen/c/struct.v @@ -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 @@ -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 @@ -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)) } @@ -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 != '' { diff --git a/vlib/v/parser/struct.v b/vlib/v/parser/struct.v index baa7c7b5a3a838..1c09398012a31c 100644 --- a/vlib/v/parser/struct.v +++ b/vlib/v/parser/struct.v @@ -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 @@ -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() @@ -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 diff --git a/vlib/v/tests/structs/struct_field_shared_test.v b/vlib/v/tests/structs/struct_field_shared_test.v new file mode 100644 index 00000000000000..5524fe9ff5d6ff --- /dev/null +++ b/vlib/v/tests/structs/struct_field_shared_test.v @@ -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 + } +}