Skip to content

Commit

Permalink
checker, cgen: allow for a shared variable, to be whole reassigned (k…
Browse files Browse the repository at this point in the history
…eeping the same mutex state) (fix #15649) (#19751)
  • Loading branch information
shove70 committed Nov 5, 2023
1 parent f82529e commit 510f091
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 7 deletions.
12 changes: 8 additions & 4 deletions vlib/v/checker/assign.v
Expand Up @@ -127,6 +127,7 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
is_blank_ident := left.is_blank_ident()
mut left_type := ast.void_type
mut var_option := false
mut is_shared_re_assign := false
if !is_decl && !is_blank_ident {
if left in [ast.Ident, ast.SelectorExpr] {
c.prevent_sum_type_unwrapping_once = true
Expand All @@ -137,6 +138,9 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
left_type = c.expr(mut left)
c.is_index_assign = false
c.expected_type = c.unwrap_generic(left_type)
is_shared_re_assign = left is ast.Ident && left.info is ast.IdentVar
&& ((left.info as ast.IdentVar).share == .shared_t || left_type.has_flag(.shared_f))
&& c.table.sym(left_type).kind in [.array, .map, .struct_]
}
if c.inside_comptime_for_field && mut left is ast.ComptimeSelector {
left_type = c.comptime_fields_default_type
Expand Down Expand Up @@ -181,7 +185,7 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
} else if right is ast.ComptimeSelector {
right_type = c.comptime_fields_default_type
}
if is_decl {
if is_decl || is_shared_re_assign {
// check generic struct init and return unwrap generic struct type
if mut right is ast.StructInit {
if right.typ.has_flag(.generic) {
Expand Down Expand Up @@ -283,7 +287,7 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
} else if left.info !is ast.IdentVar {
c.error('cannot assign to ${left.kind} `${left.name}`', left.pos)
} else {
if is_decl {
if is_decl || is_shared_re_assign {
c.check_valid_snake_case(left.name, 'variable name', left.pos)
if reserved_type_names_chk.matches(left.name) {
c.error('invalid use of reserved type `${left.name}` as a variable name',
Expand All @@ -301,9 +305,9 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
}
}
mut ident_var_info := left.info as ast.IdentVar
if ident_var_info.share == .shared_t {
if ident_var_info.share == .shared_t || is_shared_re_assign {
left_type = left_type.set_flag(.shared_f)
if is_decl {
if is_decl || is_shared_re_assign {
if left_type.nr_muls() > 1 {
c.error('shared cannot be multi level reference', left.pos)
}
Expand Down
9 changes: 6 additions & 3 deletions vlib/v/gen/c/assign.v
Expand Up @@ -459,6 +459,8 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) {
mut op_overloaded := false
mut op_expected_left := ast.Type(0)
mut op_expected_right := ast.Type(0)
is_shared_re_assign := !is_decl && node.left_types[i].has_flag(.shared_f)
&& left is ast.Ident && left_sym.kind in [.array, .map, .struct_]
if node.op == .plus_assign && unaliased_right_sym.kind == .string {
if mut left is ast.IndexExpr {
if g.table.sym(left.left_type).kind == .array_fixed {
Expand Down Expand Up @@ -608,11 +610,11 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) {
if left in [ast.Ident, ast.SelectorExpr] {
g.prevent_sum_type_unwrapping_once = true
}
if !is_fixed_array_var || is_decl {
if !is_fixed_array_var || is_decl || is_shared_re_assign {
if op_overloaded {
g.op_arg(left, op_expected_left, var_type)
} else {
if !is_decl && left.is_auto_deref_var() {
if !is_decl && !is_shared_re_assign && left.is_auto_deref_var() {
g.write('*')
}
g.expr(left)
Expand Down Expand Up @@ -728,7 +730,8 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) {
if op_overloaded {
g.op_arg(val, op_expected_right, val_type)
} else {
exp_type := if left.is_auto_deref_var() || var_type.has_flag(.shared_f) {
exp_type := if var_type.is_ptr()
&& (left.is_auto_deref_var() || var_type.has_flag(.shared_f)) {
var_type.deref()
} else {
var_type
Expand Down
36 changes: 36 additions & 0 deletions vlib/v/tests/shared_re_assign_test.v
@@ -0,0 +1,36 @@
fn test_re_assign_array() {
shared arr := [1, 2, 3]
lock arr {
arr[0] = 0
assert arr == [0, 2, 3]
arr = [0, 0, 0]
assert arr == [0, 0, 0]
}
}

struct Foo {
mut:
a int
}

fn test_re_assign_struct() {
shared st := Foo{}
lock st {
st.a = 1
assert st.a == 1
st = Foo{2}
assert st.a == 2
}
}

fn test_re_assign_map() {
shared m := map[int]int{}
lock m {
m[0] = 0
assert m[0] == 0
m = {
0: 1
}
assert m[0] == 1
}
}

0 comments on commit 510f091

Please sign in to comment.