mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
checker: check write access to shared elements of struct
and array
(#9314)
This commit is contained in:
parent
1ad4623fb8
commit
9d168895ed
@ -349,6 +349,7 @@ pub fn (c &Checker) get_default_fmt(ftyp table.Type, typ table.Type) byte {
|
||||
}
|
||||
|
||||
pub fn (mut c Checker) fail_if_unreadable(expr ast.Expr, typ table.Type, what string) {
|
||||
mut pos := token.Position{}
|
||||
match expr {
|
||||
ast.Ident {
|
||||
if typ.has_flag(.shared_f) {
|
||||
@ -361,16 +362,18 @@ pub fn (mut c Checker) fail_if_unreadable(expr ast.Expr, typ table.Type, what st
|
||||
return
|
||||
}
|
||||
ast.SelectorExpr {
|
||||
pos = expr.pos
|
||||
c.fail_if_unreadable(expr.expr, expr.expr_type, what)
|
||||
}
|
||||
ast.IndexExpr {
|
||||
pos = expr.left.position().extend(expr.pos)
|
||||
c.fail_if_unreadable(expr.left, expr.left_type, what)
|
||||
}
|
||||
else {}
|
||||
}
|
||||
if typ.has_flag(.shared_f) {
|
||||
c.error('you have to create a handle and `rlock` it to use a `shared` element as non-mut $what',
|
||||
expr.position())
|
||||
pos)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1084,6 +1084,25 @@ fn (mut c Checker) fail_if_immutable(expr ast.Expr) (string, token.Position) {
|
||||
}
|
||||
}
|
||||
ast.IndexExpr {
|
||||
left_sym := c.table.get_type_symbol(expr.left_type)
|
||||
mut elem_type := table.Type(0)
|
||||
mut kind := ''
|
||||
match left_sym.info {
|
||||
table.Array {
|
||||
elem_type, kind = left_sym.info.elem_type, 'array'
|
||||
}
|
||||
table.ArrayFixed {
|
||||
elem_type, kind = left_sym.info.elem_type, 'fixed array'
|
||||
}
|
||||
table.Map {
|
||||
elem_type, kind = left_sym.info.value_type, 'map'
|
||||
}
|
||||
else {}
|
||||
}
|
||||
if elem_type.has_flag(.shared_f) {
|
||||
c.error('you have to create a handle and `lock` it to modify `shared` $kind element',
|
||||
expr.left.position().extend(expr.pos))
|
||||
}
|
||||
to_lock, pos = c.fail_if_immutable(expr.left)
|
||||
}
|
||||
ast.ParExpr {
|
||||
@ -1128,6 +1147,11 @@ fn (mut c Checker) fail_if_immutable(expr ast.Expr) (string, token.Position) {
|
||||
c.error('field `$expr.field_name` of struct `$type_str` is immutable',
|
||||
expr.pos)
|
||||
}
|
||||
if field_info.typ.has_flag(.shared_f) {
|
||||
type_str := c.table.type_to_str(expr.expr_type)
|
||||
c.error('you have to create a handle and `lock` it to modify `shared` field `$expr.field_name` of struct `$type_str`',
|
||||
expr.pos)
|
||||
}
|
||||
to_lock, pos = c.fail_if_immutable(expr.expr)
|
||||
if to_lock != '' {
|
||||
// No automatic lock for struct access
|
||||
|
27
vlib/v/checker/tests/shared_element_lock.out
Normal file
27
vlib/v/checker/tests/shared_element_lock.out
Normal file
@ -0,0 +1,27 @@
|
||||
vlib/v/checker/tests/shared_element_lock.vv:36:5: error: you have to create a handle and `lock` it to modify `shared` field `pe` of struct `Programmer`
|
||||
34 | }
|
||||
35 | }
|
||||
36 | pr.pe.color = 3
|
||||
| ~~
|
||||
37 | shared y := pr.pe
|
||||
38 | rlock y {
|
||||
vlib/v/checker/tests/shared_element_lock.vv:42:2: error: `g` is `shared` and needs explicit lock for `v.ast.SelectorExpr`
|
||||
40 | }
|
||||
41 | shared g := Pro{}
|
||||
42 | g.pers.age = 42
|
||||
| ^
|
||||
43 | mut h := []shared Pro{len: 3}
|
||||
44 | h[2].pers.age = 42
|
||||
vlib/v/checker/tests/shared_element_lock.vv:44:2: error: you have to create a handle and `lock` it to modify `shared` array element
|
||||
42 | g.pers.age = 42
|
||||
43 | mut h := []shared Pro{len: 3}
|
||||
44 | h[2].pers.age = 42
|
||||
| ~~~~
|
||||
45 | println(h[2].pers.age)
|
||||
46 | }
|
||||
vlib/v/checker/tests/shared_element_lock.vv:45:10: error: you have to create a handle and `rlock` it to use a `shared` element as non-mut argument to print
|
||||
43 | mut h := []shared Pro{len: 3}
|
||||
44 | h[2].pers.age = 42
|
||||
45 | println(h[2].pers.age)
|
||||
| ~~~~
|
||||
46 | }
|
46
vlib/v/checker/tests/shared_element_lock.vv
Normal file
46
vlib/v/checker/tests/shared_element_lock.vv
Normal file
@ -0,0 +1,46 @@
|
||||
struct Person {
|
||||
mut:
|
||||
name string
|
||||
age int
|
||||
}
|
||||
|
||||
struct Pet {
|
||||
mut:
|
||||
name string
|
||||
color int
|
||||
}
|
||||
|
||||
struct Programmer {
|
||||
mut:
|
||||
pers Person
|
||||
pe shared Pet
|
||||
}
|
||||
|
||||
struct Pro {
|
||||
mut:
|
||||
pers Person
|
||||
pe Pet
|
||||
}
|
||||
|
||||
fn main() {
|
||||
mut pr := Programmer{
|
||||
pers: Person{
|
||||
name: 'Qwe'
|
||||
age: 44
|
||||
}
|
||||
pe: Pet{
|
||||
name: 'Ghj'
|
||||
color: 7
|
||||
}
|
||||
}
|
||||
pr.pe.color = 3
|
||||
shared y := pr.pe
|
||||
rlock y {
|
||||
println(y.color)
|
||||
}
|
||||
shared g := Pro{}
|
||||
g.pers.age = 42
|
||||
mut h := []shared Pro{len: 3}
|
||||
h[2].pers.age = 42
|
||||
println(h[2].pers.age)
|
||||
}
|
@ -78,10 +78,13 @@ fn test_shared_map_in_struct() {
|
||||
}
|
||||
|
||||
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 }
|
||||
mut a := []shared Xyz{cap: 3}
|
||||
a0 := Xyz{ n: 3 }
|
||||
a << a0
|
||||
a1 := Xyz{ n: 7 }
|
||||
a << a1
|
||||
a2 := Xyz{ n: 13 }
|
||||
a << a2
|
||||
shared p := a[0]
|
||||
shared q := a[2]
|
||||
lock q {
|
||||
|
Loading…
Reference in New Issue
Block a user