all: allow `shared` element types for `struct` and arrays (#8631)
parent
7f4c582f1a
commit
118ca1240e
|
@ -132,6 +132,7 @@ const (
|
|||
'vlib/v/tests/semaphore_timed_test.v',
|
||||
'vlib/v/tests/shared_array_test.v',
|
||||
'vlib/v/tests/shared_autolock_test.v',
|
||||
'vlib/v/tests/shared_elem_test.v',
|
||||
'vlib/v/tests/shared_lock_2_test.v',
|
||||
'vlib/v/tests/shared_lock_3_test.v',
|
||||
'vlib/v/tests/shared_fn_return_test.v',
|
||||
|
|
|
@ -652,9 +652,17 @@ pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) table.Type {
|
|||
field.pos)
|
||||
}
|
||||
}
|
||||
if info_field.typ.is_ptr() && !expr_type.is_ptr() && !expr_type.is_pointer()
|
||||
&& !expr_type.is_number() {
|
||||
c.error('ref', field.pos)
|
||||
if info_field.typ.has_flag(.shared_f) {
|
||||
if !expr_type.has_flag(.shared_f) && expr_type.is_ptr() {
|
||||
c.error('`shared` field must be initialized with `shared` or value',
|
||||
field.pos)
|
||||
}
|
||||
} else {
|
||||
if info_field.typ.is_ptr() && !expr_type.is_ptr() && !expr_type.is_pointer()
|
||||
&& !expr_type.is_number() {
|
||||
c.error('reference field must be initialized with reference',
|
||||
field.pos)
|
||||
}
|
||||
}
|
||||
struct_init.fields[i].typ = expr_type
|
||||
struct_init.fields[i].expected_type = info_field.typ
|
||||
|
|
|
@ -1489,6 +1489,9 @@ fn (mut g Gen) for_in(it ast.ForInStmt) {
|
|||
fn (mut g Gen) expr_with_cast(expr ast.Expr, got_type_raw table.Type, expected_type table.Type) {
|
||||
got_type := g.table.mktyp(got_type_raw)
|
||||
exp_sym := g.table.get_type_symbol(expected_type)
|
||||
expected_is_ptr := expected_type.is_ptr()
|
||||
got_is_ptr := got_type.is_ptr()
|
||||
got_sym := g.table.get_type_symbol(got_type)
|
||||
if exp_sym.kind == .interface_ && got_type_raw.idx() != expected_type.idx()
|
||||
&& !expected_type.has_flag(.optional) {
|
||||
got_styp := g.cc_type(got_type)
|
||||
|
@ -1506,16 +1509,13 @@ fn (mut g Gen) expr_with_cast(expr ast.Expr, got_type_raw table.Type, expected_t
|
|||
return
|
||||
}
|
||||
// cast to sum type
|
||||
exp_styp := g.typ(expected_type)
|
||||
got_styp := g.typ(got_type)
|
||||
if expected_type != table.void_type {
|
||||
expected_is_ptr := expected_type.is_ptr()
|
||||
expected_deref_type := if expected_is_ptr { expected_type.deref() } else { expected_type }
|
||||
got_is_ptr := got_type.is_ptr()
|
||||
got_deref_type := if got_is_ptr { got_type.deref() } else { got_type }
|
||||
if g.table.sumtype_has_variant(expected_deref_type, got_deref_type) {
|
||||
exp_styp := g.typ(expected_type)
|
||||
got_styp := g.typ(got_type)
|
||||
// got_idx := got_type.idx()
|
||||
got_sym := g.table.get_type_symbol(got_type)
|
||||
got_sidx := g.type_sidx(got_type)
|
||||
// TODO: do we need 1-3?
|
||||
if expected_is_ptr && got_is_ptr {
|
||||
|
@ -1560,12 +1560,28 @@ fn (mut g Gen) expr_with_cast(expr ast.Expr, got_type_raw table.Type, expected_t
|
|||
}
|
||||
}
|
||||
// Generic dereferencing logic
|
||||
expected_sym := g.table.get_type_symbol(expected_type)
|
||||
got_is_ptr := got_type.is_ptr()
|
||||
expected_is_ptr := expected_type.is_ptr()
|
||||
neither_void := table.voidptr_type !in [got_type, expected_type]
|
||||
to_shared := expected_type.has_flag(.shared_f) && !got_type_raw.has_flag(.shared_f)
|
||||
&& !expected_type.has_flag(.optional)
|
||||
// from_shared := got_type_raw.has_flag(.shared_f) && !expected_type.has_flag(.shared_f)
|
||||
if to_shared {
|
||||
shared_styp := exp_styp[0..exp_styp.len - 1] // `shared` implies ptr, so eat one `*`
|
||||
if got_type_raw.is_ptr() {
|
||||
g.error('cannot convert reference to `shared`', expr.position())
|
||||
}
|
||||
if exp_sym.kind == .array {
|
||||
g.writeln('($shared_styp*)__dup_shared_array(&($shared_styp){.val = ')
|
||||
} else if exp_sym.kind == .map {
|
||||
g.writeln('($shared_styp*)__dup_shared_map(&($shared_styp){.val = ')
|
||||
} else {
|
||||
g.writeln('($shared_styp*)__dup${shared_styp}(&($shared_styp){.val = ')
|
||||
}
|
||||
g.expr(expr)
|
||||
g.writeln('}, sizeof($shared_styp))')
|
||||
return
|
||||
}
|
||||
if got_is_ptr && !expected_is_ptr && neither_void
|
||||
&& expected_sym.kind !in [.interface_, .placeholder] {
|
||||
&& exp_sym.kind !in [.interface_, .placeholder] {
|
||||
got_deref_type := got_type.deref()
|
||||
deref_sym := g.table.get_type_symbol(got_deref_type)
|
||||
deref_will_match := expected_type in [got_type, got_deref_type, deref_sym.parent_idx]
|
||||
|
@ -4860,7 +4876,7 @@ const (
|
|||
|
||||
fn (mut g Gen) struct_init(struct_init ast.StructInit) {
|
||||
styp := g.typ(struct_init.typ)
|
||||
mut shared_styp := '' // only needed for shared &St{...
|
||||
mut shared_styp := '' // only needed for shared x := St{...
|
||||
if styp in c.skip_struct_init {
|
||||
// needed for c++ compilers
|
||||
g.go_back_out(3)
|
||||
|
@ -4873,7 +4889,7 @@ fn (mut g Gen) struct_init(struct_init ast.StructInit) {
|
|||
if is_amp {
|
||||
g.out.go_back(1) // delete the `&` already generated in `prefix_expr()
|
||||
}
|
||||
if g.is_shared && !g.inside_opt_data {
|
||||
if g.is_shared && !g.inside_opt_data && !g.is_array_set {
|
||||
mut shared_typ := struct_init.typ.set_flag(.shared_f)
|
||||
shared_styp = g.typ(shared_typ)
|
||||
g.writeln('($shared_styp*)__dup${shared_styp}(&($shared_styp){.val = ($styp){')
|
||||
|
@ -4927,8 +4943,8 @@ fn (mut g Gen) struct_init(struct_init ast.StructInit) {
|
|||
}
|
||||
}
|
||||
if !cloned {
|
||||
if field.expected_type.is_ptr() && !(field.typ.is_ptr()
|
||||
|| field.typ.is_pointer()) && !field.typ.is_number() {
|
||||
if (field.expected_type.is_ptr() && !field.expected_type.has_flag(.shared_f))
|
||||
&& !(field.typ.is_ptr() || field.typ.is_pointer()) && !field.typ.is_number() {
|
||||
g.write('/* autoref */&')
|
||||
}
|
||||
g.expr_with_cast(field.expr, field.typ, field.expected_type)
|
||||
|
@ -4993,8 +5009,9 @@ fn (mut g Gen) struct_init(struct_init ast.StructInit) {
|
|||
}
|
||||
}
|
||||
if !cloned {
|
||||
if sfield.expected_type.is_ptr() && !(sfield.typ.is_ptr()
|
||||
|| sfield.typ.is_pointer()) && !sfield.typ.is_number() {
|
||||
if (sfield.expected_type.is_ptr() && !sfield.expected_type.has_flag(.shared_f))
|
||||
&& !(sfield.typ.is_ptr() || sfield.typ.is_pointer())
|
||||
&& !sfield.typ.is_number() {
|
||||
g.write('/* autoref */&')
|
||||
}
|
||||
g.expr_with_cast(sfield.expr, sfield.typ, sfield.expected_type)
|
||||
|
@ -5045,7 +5062,7 @@ fn (mut g Gen) struct_init(struct_init ast.StructInit) {
|
|||
g.write('\n#ifndef __cplusplus\n0\n#endif\n')
|
||||
}
|
||||
g.write('}')
|
||||
if g.is_shared && !g.inside_opt_data {
|
||||
if g.is_shared && !g.inside_opt_data && !g.is_array_set {
|
||||
g.write('}, sizeof($shared_styp))')
|
||||
} else if is_amp {
|
||||
g.write(', sizeof($styp))')
|
||||
|
|
|
@ -27,7 +27,7 @@ fn (mut p Parser) array_init() ast.ArrayInit {
|
|||
line_nr := p.tok.line_nr
|
||||
p.next()
|
||||
// []string
|
||||
if p.tok.kind in [.name, .amp, .lsbr] && p.tok.line_nr == line_nr {
|
||||
if p.tok.kind in [.name, .amp, .lsbr, .key_shared] && p.tok.line_nr == line_nr {
|
||||
elem_type_pos = p.tok.position()
|
||||
elem_type = p.parse_type()
|
||||
// this is set here because it's a known type, others could be the
|
||||
|
|
|
@ -199,6 +199,9 @@ pub fn (mut p Parser) parse_type() table.Type {
|
|||
}
|
||||
is_shared := p.tok.kind == .key_shared
|
||||
is_atomic := p.tok.kind == .key_atomic
|
||||
if is_shared {
|
||||
p.register_auto_import('sync')
|
||||
}
|
||||
mut nr_muls := 0
|
||||
if p.tok.kind == .key_mut || is_shared || is_atomic {
|
||||
nr_muls++
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
struct Xyz {
|
||||
mut:
|
||||
n int
|
||||
}
|
||||
|
||||
struct Abc {
|
||||
a shared Xyz
|
||||
i int
|
||||
}
|
||||
|
||||
fn test_shared_struct_in_struct() {
|
||||
shared y := Xyz{ n: 7 }
|
||||
z := Abc{
|
||||
a: y
|
||||
}
|
||||
u := Xyz{ n: 17 }
|
||||
x := Abc{
|
||||
a: u
|
||||
}
|
||||
v := Abc{
|
||||
a: Xyz{ n: 5 }
|
||||
i: 3
|
||||
}
|
||||
shared f := x.a
|
||||
shared g := v.a
|
||||
shared h := z.a
|
||||
a := rlock f { f.n }
|
||||
b := rlock g { g.n }
|
||||
c := rlock h { h.n }
|
||||
assert a == 17
|
||||
assert b == 5
|
||||
assert c == 7
|
||||
assert v.i == 3
|
||||
}
|
||||
|
||||
struct Efg {
|
||||
a shared []f64
|
||||
i int
|
||||
}
|
||||
|
||||
fn test_shared_array_in_struct() {
|
||||
x := Efg{
|
||||
a: [1.25, 2.75, 7, 13.0625]
|
||||
i: 12
|
||||
}
|
||||
shared t := x.a
|
||||
lock t {
|
||||
t[2] = -1.125
|
||||
}
|
||||
shared tt := x.a
|
||||
v := rlock tt { tt[3] }
|
||||
w := rlock tt { tt[2] }
|
||||
assert v == 13.0625
|
||||
assert w == -1.125
|
||||
assert x.i == 12
|
||||
}
|
||||
|
||||
struct Hjk {
|
||||
m shared map[string]f64
|
||||
i int
|
||||
}
|
||||
|
||||
fn test_shared_map_in_struct() {
|
||||
x := Hjk{
|
||||
m: {'st': -6.0625, 'xy': 12.125, 'rz': 2.25}
|
||||
i: 23
|
||||
}
|
||||
shared k := x.m
|
||||
lock k {
|
||||
k['yxc'] = -23.5
|
||||
}
|
||||
shared p := x.m
|
||||
a := rlock p { p['xy'] }
|
||||
b := rlock p { p['yxc'] }
|
||||
assert a == 12.125
|
||||
assert b == -23.5
|
||||
assert x.i == 23
|
||||
}
|
||||
|
||||
fn test_array_of_shared() {
|
||||
mut a := []shared Xyz{len: 3}
|
||||
a[0] = Xyz{ n: 3 }
|
||||
a[1] = Xyz{ n: 7 }
|
||||
a[2] = Xyz{ n: 13 }
|
||||
shared p := a[0]
|
||||
shared q := a[2]
|
||||
lock q {
|
||||
q.n = -17
|
||||
}
|
||||
shared r := a[2]
|
||||
e := rlock p { p.n }
|
||||
f := rlock r { r.n }
|
||||
assert e == 3
|
||||
assert f == -17
|
||||
}
|
Loading…
Reference in New Issue