From 1c9950c84a238b415b27d147cdeef6283df28542 Mon Sep 17 00:00:00 2001
From: yuyi <yuyi98@163.com>
Date: Mon, 25 Jan 2021 20:40:53 +0800
Subject: [PATCH] cgen: fix map_complex_high_order_fixed_array (#8329)

---
 vlib/v/gen/cgen.v                           | 83 +++++++--------------
 vlib/v/tests/map_complex_fixed_array_test.v |  9 +++
 2 files changed, 37 insertions(+), 55 deletions(-)

diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v
index 8ba1d5fe3f..92002bb076 100644
--- a/vlib/v/gen/cgen.v
+++ b/vlib/v/gen/cgen.v
@@ -61,10 +61,11 @@ mut:
 	is_assign_lhs       bool // inside left part of assign expr (for array_set(), etc)
 	is_assign_rhs       bool // inside right part of assign after `=` (val expr)
 	is_array_set        bool
-	is_amp              bool     // for `&Foo{}` to merge PrefixExpr `&` and StructInit `Foo{}`; also for `&byte(0)` etc
-	is_sql              bool     // Inside `sql db{}` statement, generating sql instead of C (e.g. `and` instead of `&&` etc)
-	is_shared           bool     // for initialization of hidden mutex in `[rw]shared` literals
-	is_vlines_enabled   bool     // is it safe to generate #line directives when -g is passed
+	is_amp              bool // for `&Foo{}` to merge PrefixExpr `&` and StructInit `Foo{}`; also for `&byte(0)` etc
+	is_sql              bool // Inside `sql db{}` statement, generating sql instead of C (e.g. `and` instead of `&&` etc)
+	is_shared           bool // for initialization of hidden mutex in `[rw]shared` literals
+	is_vlines_enabled   bool // is it safe to generate #line directives when -g is passed
+	array_set_pos       int
 	vlines_path         string   // set to the proper path for generating #line directives
 	optionals           []string // to avoid duplicates TODO perf, use map
 	chan_pop_optionals  []string // types for `x := <-ch or {...}`
@@ -1976,57 +1977,28 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
 			}
 		} else if is_fixed_array_init && assign_stmt.op == .assign {
 			right := val as ast.ArrayInit
-			if right.has_val {
-				for j, expr in right.exprs {
-					if !is_decl && left is ast.Ident
-						&& g.for_in_mul_val_name == (left as ast.Ident).name {
-						g.write('(*')
-						g.expr(left)
-						g.write(')')
-					} else {
-						g.expr(left)
-					}
-					if g.is_array_set {
-						g.out.go_back(2)
-					} else {
-						g.write('[$j] = ')
-					}
-					g.expr(expr)
-					if g.is_array_set {
-						g.writeln(')')
-						g.is_array_set = false
-					} else {
-						g.writeln(';')
-					}
-				}
+			v_var := g.new_tmp_var()
+			arr_typ := styp.trim('*')
+			g.write('$arr_typ $v_var = ')
+			g.expr(right)
+			g.writeln(';')
+			pos := g.out.len
+			g.expr(left)
+
+			if g.is_array_set && g.array_set_pos > 0 {
+				g.out.go_back_to(g.array_set_pos)
+				g.write(', &$v_var)')
+				g.is_array_set = false
+				g.array_set_pos = 0
 			} else {
-				fixed_array := right_sym.info as table.ArrayFixed
-				for j in 0 .. fixed_array.size {
-					if !is_decl && left is ast.Ident
-						&& g.for_in_mul_val_name == (left as ast.Ident).name {
-						g.write('(*')
-						g.expr(left)
-						g.write(')')
-					} else {
-						g.expr(left)
-					}
-					if g.is_array_set {
-						g.out.go_back(2)
-					} else {
-						g.write('[$j] = ')
-					}
-					if right.has_default {
-						g.expr(right.default_expr)
-					} else {
-						g.write(g.type_default(right.elem_type))
-					}
-					if g.is_array_set {
-						g.writeln(')')
-						g.is_array_set = false
-					} else {
-						g.writeln(';')
-					}
-				}
+				g.out.go_back_to(pos)
+				is_var_mut := !is_decl && left is ast.Ident
+					&& g.for_in_mul_val_name == (left as ast.Ident).name
+				addr := if is_var_mut { '' } else { '&' }
+				g.writeln('')
+				g.write('memcpy($addr')
+				g.expr(left)
+				g.writeln(', &$v_var, sizeof($arr_typ));')
 			}
 			g.is_assign_lhs = false
 		} else {
@@ -2142,7 +2114,7 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
 				if is_fixed_array_copy {
 					i_var := g.new_tmp_var()
 					fixed_array := right_sym.info as table.ArrayFixed
-					g.write('for(int $i_var=0; $i_var<$fixed_array.size; $i_var++) {')
+					g.write('for (int $i_var=0; $i_var<$fixed_array.size; $i_var++) {')
 					g.expr(left)
 					g.write('[$i_var] = ')
 					g.expr(val)
@@ -4271,6 +4243,7 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) {
 					if elem_typ.kind == .function {
 						g.write(', &(voidptr[]) { ')
 					} else {
+						g.array_set_pos = g.out.len
 						g.write(', &($elem_type_str[]) { ')
 					}
 					if g.assign_op != .assign && info.value_type != table.string_type {
diff --git a/vlib/v/tests/map_complex_fixed_array_test.v b/vlib/v/tests/map_complex_fixed_array_test.v
index 8afceb4954..68db45af84 100644
--- a/vlib/v/tests/map_complex_fixed_array_test.v
+++ b/vlib/v/tests/map_complex_fixed_array_test.v
@@ -17,3 +17,12 @@ fn test_innermost_value_of_map_fixed_array() {
 	assert m['foo'][0][0]['bar'] == 1
 	assert '${m['foo'][0][0]['bar']}' == '1'
 }
+
+fn test_complex_map_high_order_fixed_array() {
+	mut m := {'foo': [[{'a': 1}]!]!, 'bar': [[{'b': 2}]!]!}
+	for _, mut j in m {
+		j = [[{'c': 3}]!]!
+	}
+	println(m)
+	assert '$m' == "{'foo': [[{'c': 3}]], 'bar': [[{'c': 3}]]}"
+}