checker: require `shared a` to be `rlocked` to read `a[i]` or `a.e` (#9266)

pull/9269/head
Uwe Krüger 2021-03-12 16:08:39 +01:00 committed by GitHub
parent def53fd73f
commit dbbf96702b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 78 additions and 26 deletions

View File

@ -348,14 +348,27 @@ pub fn (c &Checker) get_default_fmt(ftyp table.Type, typ table.Type) byte {
}
}
pub fn (mut c Checker) fail_if_not_rlocked(expr ast.Expr, what string) {
if expr is ast.Ident {
if expr.name !in c.rlocked_names && expr.name !in c.locked_names {
action := if what == 'argument' { 'passed' } else { 'used' }
c.error('$expr.name is `shared` and must be `rlock`ed or `lock`ed to be $action as non-mut $what',
expr.pos)
pub fn (mut c Checker) fail_if_unreadable(expr ast.Expr, typ table.Type, what string) {
match expr {
ast.Ident {
if typ.has_flag(.shared_f) {
if expr.name !in c.rlocked_names && expr.name !in c.locked_names {
action := if what == 'argument' { 'passed' } else { 'used' }
c.error('$expr.name is `shared` and must be `rlock`ed or `lock`ed to be $action as non-mut $what',
expr.pos)
}
}
return
}
} else {
ast.SelectorExpr {
c.fail_if_unreadable(expr.expr, expr.expr_type, what)
}
ast.IndexExpr {
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())
}
@ -366,9 +379,7 @@ pub fn (mut c Checker) string_inter_lit(mut node ast.StringInterLiteral) table.T
c.inside_println_arg = true
for i, expr in node.exprs {
ftyp := c.expr(expr)
if ftyp.has_flag(.shared_f) {
c.fail_if_not_rlocked(expr, 'interpolation object')
}
c.fail_if_unreadable(expr, ftyp, 'interpolation object')
node.expr_types << ftyp
typ := c.table.unalias_num_type(ftyp)
mut fmt := node.fmts[i]

View File

@ -1421,9 +1421,7 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type {
pos)
}
} else {
if left_type.has_flag(.shared_f) {
c.fail_if_not_rlocked(call_expr.left, 'receiver')
}
c.fail_if_unreadable(call_expr.left, left_type, 'receiver')
}
if (!left_type_sym.is_builtin() && method.mod != 'builtin') && method.language == .v
&& method.no_body {
@ -1517,9 +1515,7 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type {
c.error('`$call_expr.name` parameter `$param.name` is `$tok`, you need to provide `$tok` e.g. `$tok arg${
i + 1}`', arg.expr.position())
} else {
if got_arg_typ.has_flag(.shared_f) {
c.fail_if_not_rlocked(arg.expr, 'argument')
}
c.fail_if_unreadable(arg.expr, got_arg_typ, 'argument')
}
}
}
@ -1584,9 +1580,7 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type {
if call_expr.args.len > 0 {
c.error('.str() method calls should have no arguments', call_expr.pos)
}
if left_type.has_flag(.shared_f) {
c.fail_if_not_rlocked(call_expr.left, 'receiver')
}
c.fail_if_unreadable(call_expr.left, left_type, 'receiver')
return table.string_type
}
// call struct field fn type
@ -1903,9 +1897,7 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type {
if call_expr.args[0].typ.is_void() {
c.error('`$fn_name` can not print void expressions', call_expr.pos)
}
if call_expr.args[0].typ.has_flag(.shared_f) {
c.fail_if_not_rlocked(call_expr.args[0].expr, 'argument to print')
}
c.fail_if_unreadable(call_expr.args[0].expr, call_expr.args[0].typ, 'argument to print')
c.inside_println_arg = false
/*
// TODO: optimize `struct T{} fn (t &T) str() string {return 'abc'} mut a := []&T{} a << &T{} println(a[0])`
@ -1983,9 +1975,7 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type {
c.error('`$call_expr.name` parameter `$arg.name` is `$tok`, you need to provide `$tok` e.g. `$tok arg${
i + 1}`', call_arg.expr.position())
} else {
if typ.has_flag(.shared_f) {
c.fail_if_not_rlocked(call_arg.expr, 'argument')
}
c.fail_if_unreadable(call_arg.expr, typ, 'argument')
}
}
// Handle expected interface

View File

@ -5,3 +5,9 @@ vlib/v/checker/tests/lock_already_locked.vv:11:3: error: nested `lock`/`rlock` n
| ~~~~~
12 | a.x++
13 | }
vlib/v/checker/tests/lock_already_locked.vv:15:10: error: a is `shared` and must be `rlock`ed or `lock`ed to be used as non-mut argument to print
13 | }
14 | }
15 | println(a.x)
| ^
16 | }

View File

@ -5,3 +5,9 @@ vlib/v/checker/tests/lock_already_rlocked.vv:11:3: error: nested `lock`/`rlock`
| ~~~~
12 | a.x++
13 | }
vlib/v/checker/tests/lock_already_rlocked.vv:15:10: error: a is `shared` and must be `rlock`ed or `lock`ed to be used as non-mut argument to print
13 | }
14 | }
15 | println(a.x)
| ^
16 | }

View File

@ -1,7 +1,27 @@
vlib/v/checker/tests/lock_needed.vv:10:2: error: `abc` is `shared` and needs explicit lock for `v.ast.SelectorExpr`
vlib/v/checker/tests/lock_needed.vv:10:2: error: `abc` is `shared` and needs explicit lock for `v.ast.SelectorExpr`
8 | x: 5
9 | }
10 | abc.x++
| ~~~
11 | println(abc.x)
12 | }
vlib/v/checker/tests/lock_needed.vv:11:10: error: abc is `shared` and must be `rlock`ed or `lock`ed to be used as non-mut argument to print
9 | }
10 | abc.x++
11 | println(abc.x)
| ~~~
12 | }
13 |
vlib/v/checker/tests/lock_needed.vv:25:12: error: you have to create a handle and `rlock` it to use a `shared` element as non-mut argument to print
23 | }
24 | }
25 | println(a.st.x)
| ~~
26 | }
27 |
vlib/v/checker/tests/lock_needed.vv:30:10: error: a is `shared` and must be `rlock`ed or `lock`ed to be used as non-mut argument to print
28 | fn g() {
29 | shared a := []f64{len: 10, init: 7.5}
30 | println(a[3])
| ^
31 | }

View File

@ -10,3 +10,22 @@ fn main() {
abc.x++
println(abc.x)
}
struct Abc {
mut:
st shared St
}
fn f() {
mut a := Abc{
st: St{
x: 9
}
}
println(a.st.x)
}
fn g() {
shared a := []f64{len: 10, init: 7.5}
println(a[3])
}