diff --git a/vlib/v/checker/assign.v b/vlib/v/checker/assign.v index 4a064b0495..c658a3a567 100644 --- a/vlib/v/checker/assign.v +++ b/vlib/v/checker/assign.v @@ -164,6 +164,12 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) { mut right := if i < node.right.len { node.right[i] } else { node.right[0] } mut right_type := node.right_types[i] if mut right is ast.Ident { + // resolve shared right vairable + if right_type.has_flag(.shared_f) { + if c.fail_if_unreadable(right, right_type, 'right-hand side of assignment') { + return + } + } right_sym := c.table.sym(right_type) if right_sym.info is ast.Struct { if right_sym.info.generic_types.len > 0 { diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index d0c2715671..738386b30c 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -4664,7 +4664,8 @@ fn (mut c Checker) ensure_type_exists(typ ast.Type, pos token.Pos) ? { } } -fn (mut c Checker) fail_if_unreadable(expr ast.Expr, typ ast.Type, what string) { +// return true if a violation of a shared variable access rule is detected +fn (mut c Checker) fail_if_unreadable(expr ast.Expr, typ ast.Type, what string) bool { mut pos := token.Pos{} match expr { ast.Ident { @@ -4673,9 +4674,10 @@ fn (mut c Checker) fail_if_unreadable(expr ast.Expr, typ ast.Type, what string) 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 true } } - return + return false } ast.SelectorExpr { pos = expr.pos @@ -4685,31 +4687,42 @@ fn (mut c Checker) fail_if_unreadable(expr ast.Expr, typ ast.Type, what string) 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 true } - return + return false } else { - c.fail_if_unreadable(expr.expr, expr.expr_type, what) + if c.fail_if_unreadable(expr.expr, expr.expr_type, what) { + return true + } } } ast.CallExpr { pos = expr.pos if expr.is_method { - c.fail_if_unreadable(expr.left, expr.left_type, what) + if c.fail_if_unreadable(expr.left, expr.left_type, what) { + return true + } } - return + return false } ast.LockExpr { // TODO: check expressions inside the lock by appending to c.(r)locked_names - return + return false } ast.IndexExpr { pos = expr.left.pos().extend(expr.pos) - c.fail_if_unreadable(expr.left, expr.left_type, what) + if c.fail_if_unreadable(expr.left, expr.left_type, what) { + return true + } } ast.InfixExpr { pos = expr.left.pos().extend(expr.pos) - c.fail_if_unreadable(expr.left, expr.left_type, what) - c.fail_if_unreadable(expr.right, expr.right_type, what) + if c.fail_if_unreadable(expr.left, expr.left_type, what) { + return true + } + if c.fail_if_unreadable(expr.right, expr.right_type, what) { + return true + } } else { pos = expr.pos() @@ -4718,7 +4731,9 @@ fn (mut c Checker) fail_if_unreadable(expr ast.Expr, typ ast.Type, what string) 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}', pos) + return true } + return false } fn (mut c Checker) fail_if_stack_struct_action_outside_unsafe(mut ident ast.Ident, failed_action string) { diff --git a/vlib/v/checker/tests/shared_param_assign_err.out b/vlib/v/checker/tests/shared_param_assign_err.out new file mode 100644 index 0000000000..f2363c66a1 --- /dev/null +++ b/vlib/v/checker/tests/shared_param_assign_err.out @@ -0,0 +1,13 @@ +vlib/v/checker/tests/shared_param_assign_err.vv:2:10: error: `arr` is `shared` and must be `rlock`ed or `lock`ed to be used as non-mut right-hand side of assignment + 1 | fn foo(shared arr []string) { + 2 | arr2 := arr + | ~~~ + 3 | println(arr2) + 4 | } +vlib/v/checker/tests/shared_param_assign_err.vv:3:10: error: `arr2` is `shared` and must be `rlock`ed or `lock`ed to be used as non-mut argument to print + 1 | fn foo(shared arr []string) { + 2 | arr2 := arr + 3 | println(arr2) + | ~~~~ + 4 | } + 5 | diff --git a/vlib/v/checker/tests/shared_param_assign_err.vv b/vlib/v/checker/tests/shared_param_assign_err.vv new file mode 100644 index 0000000000..d65f2567bf --- /dev/null +++ b/vlib/v/checker/tests/shared_param_assign_err.vv @@ -0,0 +1,9 @@ +fn foo(shared arr []string) { + arr2 := arr + println(arr2) +} + +fn main() { + shared arr := [''] + foo(shared arr) +}