From 94217571cd059b15382952074993e8782668e126 Mon Sep 17 00:00:00 2001 From: yuyi Date: Sat, 20 May 2023 07:23:50 +0800 Subject: [PATCH] parser, checker, cgen: fix swapping arrays (#18204) --- vlib/v/checker/assign.v | 2 +- vlib/v/gen/c/assign.v | 52 +++++++++++++++++++++++++++------- vlib/v/parser/assign.v | 3 ++ vlib/v/tests/swap_array_test.v | 19 +++++++++++++ 4 files changed, 64 insertions(+), 12 deletions(-) create mode 100644 vlib/v/tests/swap_array_test.v diff --git a/vlib/v/checker/assign.v b/vlib/v/checker/assign.v index 5906de76ee..dd31975b17 100644 --- a/vlib/v/checker/assign.v +++ b/vlib/v/checker/assign.v @@ -258,7 +258,7 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) { if !is_decl && left is ast.Ident && !is_blank_ident && !left_type.is_real_pointer() && right_type.is_real_pointer() && !right_type.has_flag(.shared_f) { left_sym := c.table.sym(left_type) - if left_sym.kind != .function { + if left_sym.kind !in [.function, .array] { c.warn( 'cannot assign a reference to a value (this will be an error soon) left=${c.table.type_str(left_type)} ${left_type.is_ptr()} ' + 'right=${c.table.type_str(right_type)} ${right_type.is_real_pointer()} ptr=${right_type.is_ptr()}', diff --git a/vlib/v/gen/c/assign.v b/vlib/v/gen/c/assign.v index 04cbe44084..68012552d0 100644 --- a/vlib/v/gen/c/assign.v +++ b/vlib/v/gen/c/assign.v @@ -843,6 +843,7 @@ fn (mut g Gen) gen_assign_vars_autofree(node &ast.AssignStmt) { fn (mut g Gen) gen_cross_var_assign(node &ast.AssignStmt) { for i, left in node.left { + left_is_auto_deref_var := left.is_auto_deref_var() match left { ast.Ident { left_typ := node.left_types[i] @@ -851,9 +852,20 @@ fn (mut g Gen) gen_cross_var_assign(node &ast.AssignStmt) { if left_sym.kind == .function { g.write_fn_ptr_decl(left_sym.info as ast.FnType, '_var_${left.pos.pos}') g.writeln(' = ${anon_ctx}${c_name(left.name)};') + } else if left_is_auto_deref_var { + styp := g.typ(left_typ).trim('*') + if left_sym.kind == .array { + g.writeln('${styp} _var_${left.pos.pos} = array_clone(${anon_ctx}${c_name(left.name)});') + } else { + g.writeln('${styp} _var_${left.pos.pos} = *${anon_ctx}${c_name(left.name)};') + } } else { styp := g.typ(left_typ) - g.writeln('${styp} _var_${left.pos.pos} = ${anon_ctx}${c_name(left.name)};') + if left_sym.kind == .array { + g.writeln('${styp} _var_${left.pos.pos} = array_clone(&${anon_ctx}${c_name(left.name)});') + } else { + g.writeln('${styp} _var_${left.pos.pos} = ${anon_ctx}${c_name(left.name)};') + } } } ast.IndexExpr { @@ -1009,18 +1021,36 @@ fn (mut g Gen) gen_cross_tmp_variable(left []ast.Expr, val ast.Expr) { g.write(')') } ast.CallExpr { - mut fn_name := val.name.replace('.', '__') - if val.concrete_types.len > 0 { - fn_name = g.generic_fn_name(val.concrete_types, fn_name) - } - g.write('${fn_name}(') - for i, arg in val.args { - g.gen_cross_tmp_variable(left, arg.expr) - if i != val.args.len - 1 { - g.write(', ') + if val.is_method { + rec_cc_type := g.cc_type(val.receiver_type, false) + mut rec_typ_name := util.no_dots(rec_cc_type) + if g.table.sym(val.receiver_type).kind == .array { + rec_typ_name = 'array' } + fn_name := util.no_dots('${rec_typ_name}_${val.name}') + g.write('${fn_name}(&') + g.gen_cross_tmp_variable(left, val.left) + for i, arg in val.args { + g.gen_cross_tmp_variable(left, arg.expr) + if i != val.args.len - 1 { + g.write(', ') + } + } + g.write(')') + } else { + mut fn_name := val.name.replace('.', '__') + if val.concrete_types.len > 0 { + fn_name = g.generic_fn_name(val.concrete_types, fn_name) + } + g.write('${fn_name}(') + for i, arg in val.args { + g.gen_cross_tmp_variable(left, arg.expr) + if i != val.args.len - 1 { + g.write(', ') + } + } + g.write(')') } - g.write(')') } ast.PrefixExpr { g.write(val.op.str()) diff --git a/vlib/v/parser/assign.v b/vlib/v/parser/assign.v index 99a2c226b8..7739f75c52 100644 --- a/vlib/v/parser/assign.v +++ b/vlib/v/parser/assign.v @@ -157,6 +157,9 @@ fn (mut p Parser) check_cross_variables(exprs []ast.Expr, val ast.Expr) bool { return p.check_cross_variables(exprs, val.expr) } ast.CallExpr { + if p.check_cross_variables(exprs, val.left) { + return true + } for arg in val.args { if p.check_cross_variables(exprs, arg.expr) { return true diff --git a/vlib/v/tests/swap_array_test.v b/vlib/v/tests/swap_array_test.v new file mode 100644 index 0000000000..882d8e7bc2 --- /dev/null +++ b/vlib/v/tests/swap_array_test.v @@ -0,0 +1,19 @@ +fn test_swap_array() { + mut array1 := []int{len: 10, init: 1} + + println(array1) + swaper(mut array1) + println(array1) + + assert array1 == [22, 2, 2, 2, 2, 2, 2, 2, 2, 2] +} + +fn swaper(mut array1 []int) { + mut array2 := []int{len: 10, init: 2} + array1[0] = 11 + array2[0] = 22 + + unsafe { + array1, array2 = array2, array1 + } +}