all: allow `shared` element types for `struct` and arrays (#8631)

pull/8634/head
Uwe Krüger 2021-02-08 00:28:29 +01:00 committed by GitHub
parent 7f4c582f1a
commit 118ca1240e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 144 additions and 20 deletions

View File

@ -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',

View File

@ -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

View File

@ -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))')

View File

@ -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

View File

@ -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++

View File

@ -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
}