From 510f0915b1021f5a7b5d0973cfa5f8112db736d9 Mon Sep 17 00:00:00 2001 From: shove Date: Sun, 5 Nov 2023 21:15:14 +0800 Subject: [PATCH] checker, cgen: allow for a shared variable, to be whole reassigned (keeping the same mutex state) (fix #15649) (#19751) --- vlib/v/checker/assign.v | 12 ++++++---- vlib/v/gen/c/assign.v | 9 ++++--- vlib/v/tests/shared_re_assign_test.v | 36 ++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 7 deletions(-) create mode 100644 vlib/v/tests/shared_re_assign_test.v diff --git a/vlib/v/checker/assign.v b/vlib/v/checker/assign.v index c4ecea31bd..ac40e3fcf8 100644 --- a/vlib/v/checker/assign.v +++ b/vlib/v/checker/assign.v @@ -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 @@ -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 @@ -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) { @@ -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', @@ -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) } diff --git a/vlib/v/gen/c/assign.v b/vlib/v/gen/c/assign.v index a8df4a0df2..479d58bd67 100644 --- a/vlib/v/gen/c/assign.v +++ b/vlib/v/gen/c/assign.v @@ -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 { @@ -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) @@ -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 diff --git a/vlib/v/tests/shared_re_assign_test.v b/vlib/v/tests/shared_re_assign_test.v new file mode 100644 index 0000000000..427490e288 --- /dev/null +++ b/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 + } +}