From 982e35909d29b342a192b7d877b88f4a4b6dddfb Mon Sep 17 00:00:00 2001 From: yuyi Date: Tue, 16 Feb 2021 20:24:19 +0800 Subject: [PATCH] cgen: fix `mut` var in `for` loop reads as address (fix #8548) (#8745) --- vlib/v/checker/checker.v | 28 ++++-- vlib/v/gen/c/array.v | 3 + vlib/v/gen/c/cgen.v | 25 ++++- vlib/v/gen/c/str.v | 15 +++ vlib/v/tests/mut_test.v | 207 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 269 insertions(+), 9 deletions(-) diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index bd9c8f7e7d..33f16a8e9c 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -763,7 +763,7 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type { left_pos := infix_expr.left.position() right_pos := infix_expr.right.position() if (left_type.is_ptr() || left.is_pointer()) && infix_expr.op in [.plus, .minus] { - if !c.inside_unsafe { + if !c.inside_unsafe && !infix_expr.left.is_mut_ident() && !infix_expr.right.is_mut_ident() { c.warn('pointer arithmetic is only allowed in `unsafe` blocks', left_pos) } if left_type == table.voidptr_type { @@ -2600,7 +2600,11 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) { right := if i < assign_stmt.right.len { assign_stmt.right[i] } else { assign_stmt.right[0] } mut right_type := assign_stmt.right_types[i] if is_decl { - left_type = c.table.mktyp(right_type) + if right.is_mut_ident() { + left_type = c.table.mktyp(right_type.deref()) + } else { + left_type = c.table.mktyp(right_type) + } if left_type == table.int_type { if right is ast.IntegerLiteral { mut is_large := right.val.len > 13 @@ -3007,7 +3011,11 @@ pub fn (mut c Checker) array_init(mut array_init ast.ArrayInit) table.Type { } // The first element's type if i == 0 { - elem_type = c.table.mktyp(typ) + if expr.is_mut_ident() { + elem_type = c.table.mktyp(typ.deref()) + } else { + elem_type = c.table.mktyp(typ) + } c.expected_type = elem_type continue } @@ -5097,7 +5105,7 @@ pub fn (mut c Checker) postfix_expr(mut node ast.PostfixExpr) table.Type { typ := c.expr(node.expr) typ_sym := c.table.get_type_symbol(typ) is_non_void_pointer := (typ.is_ptr() || typ.is_pointer()) && typ_sym.kind != .voidptr - if !c.inside_unsafe && is_non_void_pointer { + if !c.inside_unsafe && is_non_void_pointer && !node.expr.is_mut_ident() { c.warn('pointer arithmetic is only allowed in `unsafe` blocks', node.pos) } if !(typ_sym.is_number() || (c.inside_unsafe && is_non_void_pointer)) { @@ -5224,7 +5232,7 @@ pub fn (mut c Checker) index_expr(mut node ast.IndexExpr) table.Type { '(note, that variables may be mutable but string values are always immutable, like in Go and Java)', node.pos) } - if !c.inside_unsafe && (typ.is_ptr() || typ.is_pointer()) { + if !c.inside_unsafe && ((typ.is_ptr() && !node.left.is_mut_ident()) || typ.is_pointer()) { mut is_ok := false if mut node.left is ast.Ident { if node.left.obj is ast.Var { @@ -5403,8 +5411,14 @@ pub fn (mut c Checker) map_init(mut node ast.MapInit) table.Type { return node.typ } // `{'age': 20}` - key0_type := c.table.mktyp(c.expr(node.keys[0])) - val0_type := c.table.mktyp(c.expr(node.vals[0])) + mut key0_type := c.table.mktyp(c.expr(node.keys[0])) + if node.keys[0].is_mut_ident() { + key0_type = key0_type.deref() + } + mut val0_type := c.table.mktyp(c.expr(node.vals[0])) + if node.vals[0].is_mut_ident() { + val0_type = val0_type.deref() + } mut same_key_type := true for i, key in node.keys { if i == 0 { diff --git a/vlib/v/gen/c/array.v b/vlib/v/gen/c/array.v index bde6ddcc1a..7b44ad8c0e 100644 --- a/vlib/v/gen/c/array.v +++ b/vlib/v/gen/c/array.v @@ -26,6 +26,9 @@ fn (mut g Gen) array_init(node ast.ArrayInit) { g.write('{') if node.has_val { for i, expr in node.exprs { + if expr.is_mut_ident() { + g.write('*') + } g.expr(expr) if i != node.exprs.len - 1 { g.write(', ') diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 6484df5dc9..12e46e0962 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -1525,7 +1525,7 @@ fn (mut g Gen) expr_with_cast(expr ast.Expr, got_type_raw table.Type, expected_t return } if got_is_ptr && !expected_is_ptr && neither_void - && exp_sym.kind !in [.interface_, .placeholder] { + && exp_sym.kind !in [.interface_, .placeholder] && expr !is ast.InfixExpr { got_deref_type := got_type.deref() deref_sym := g.table.get_type_symbol(got_deref_type) deref_will_match := expected_type in [got_type, got_deref_type, deref_sym.parent_idx] @@ -2111,6 +2111,9 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) { g.write('for (int $i_var=0; $i_var<$fixed_array.size; $i_var++) {') g.expr(left) g.write('[$i_var] = ') + if val.is_mut_ident() { + g.write('*') + } g.expr(val) g.write('[$i_var];') g.writeln('}') @@ -2133,6 +2136,9 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) { g.write('{0}') } } else { + if val.is_mut_ident() { + g.write('*') + } g.expr(val) } } else { @@ -2715,7 +2721,13 @@ fn (mut g Gen) expr(node ast.Expr) { g.writeln('sync__RwMutex_lock(&$node.auto_locked->mtx);') } g.inside_map_postfix = true - g.expr(node.expr) + if node.expr.is_mut_ident() { + g.write('(*') + g.expr(node.expr) + g.write(')') + } else { + g.expr(node.expr) + } g.inside_map_postfix = false g.write(node.op.str()) if node.auto_locked != '' { @@ -3375,8 +3387,14 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) { if need_par { g.write('(') } + if node.left_type.is_ptr() && node.left.is_mut_ident() { + g.write('*') + } g.expr(node.left) g.write(' $node.op.str() ') + if node.right_type.is_ptr() && node.right.is_mut_ident() { + g.write('*') + } g.expr(node.right) if need_par { g.write(')') @@ -3706,6 +3724,9 @@ fn (mut g Gen) map_init(node ast.MapInit) { g.write('}), _MOV(($value_typ_str[$size]){') } for expr in node.vals { + if expr.is_mut_ident() { + g.write('*') + } g.expr(expr) g.write(', ') } diff --git a/vlib/v/gen/c/str.v b/vlib/v/gen/c/str.v index 22102e974f..9be99b6f27 100644 --- a/vlib/v/gen/c/str.v +++ b/vlib/v/gen/c/str.v @@ -264,9 +264,15 @@ fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) { if typ == table.string_type { if g.inside_vweb_tmpl { g.write('vweb__filter(') + if expr.is_mut_ident() { + g.write('*') + } g.expr(expr) g.write(')') } else { + if expr.is_mut_ident() { + g.write('*') + } g.expr(expr) } } else if node.fmts[i] == `s` || typ.has_flag(.variadic) { @@ -283,12 +289,21 @@ fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) { } else { g.write('(u64)(') } + if expr.is_mut_ident() { + g.write('*') + } g.expr(expr) g.write(')') } else { + if expr.is_mut_ident() { + g.write('*') + } g.expr(expr) } } else { + if expr.is_mut_ident() { + g.write('*') + } g.expr(expr) } if node.fmts[i] == `s` && node.fwidths[i] != 0 { diff --git a/vlib/v/tests/mut_test.v b/vlib/v/tests/mut_test.v index f4e5f02c74..4859740dc9 100644 --- a/vlib/v/tests/mut_test.v +++ b/vlib/v/tests/mut_test.v @@ -47,3 +47,210 @@ fn test_mut_2() { assert b.a[0].v[3] == 8 assert b.a[0].v[4] == 5 } + +fn test_mut_3() { + mut indices := []int{len: 3} + mut results := []string{} + + for i, mut v in indices { + v = i + a := v + println('$i $v $a') + results << '$i $v $a' + } + assert results[0] == '0 0 0' + assert results[1] == '1 1 1' + assert results[2] == '2 2 2' +} + +struct St { +mut: + n int +} + +fn f(mut x St) { + mut y := St{n: 2} + a := x + b := y + x.n = 3 + y.n = 4 + println('$a.n $b.n') + assert '$a.n $b.n' == '1 2' +} + +fn test_mut_4() { + mut x := St{ n: 1 } + f(mut x) +} + +fn test_mut_5() { + mut arr1 := []int{len:2} + mut arr2 := []int{len:2} + mut results := []string{} + + for i, mut v in arr1 { + for ii, mut vv in arr2 { + v = i + a := v + println('$i $v $a') + results << '$i $v $a' + + vv = ii + aa := vv + println('$ii $vv $aa') + results << "$ii $vv $aa" + } + } + + assert results[0] == '0 0 0' + assert results[1] == '0 0 0' + assert results[2] == '0 0 0' + assert results[3] == '1 1 1' + assert results[4] == '1 1 1' + assert results[5] == '0 0 0' + assert results[6] == '1 1 1' + assert results[7] == '1 1 1' +} + +fn test_mut_6() { + mut results := []int{} + mut arr := []int{len:3} + for _, mut v in arr { + v = v + 1 + println(v) + results << v + } + assert results[0] == 1 + assert results[1] == 1 + assert results[2] == 1 +} + +fn test_mut_7() { + mut arr := []int{len:3} + mut results := []int{} + for _, mut v in arr { + v = v + 1 // v: 1 + mut vv := v // vv: 1, v: 1 + vv = vv + v // vv: 2, v: 1 + println(v) + println(vv) + results << v + results << vv + } + assert results[0] == 1 + assert results[1] == 2 + assert results[2] == 1 + assert results[3] == 2 + assert results[4] == 1 + assert results[5] == 2 +} + +fn test_mut_8() { + mut indices := []int{len: 1} + for i, mut v in indices { + v = i + mut b := v + println(typeof(i).name) + println(typeof(v).name) + println(typeof(b).name) + u := [v, 5, 6] + println(typeof(u).name) + println(u) + assert typeof(b).name == 'int' + assert typeof(u).name == '[]int' + assert u == [0, 5, 6] + } +} + +fn test_mut_9() { + mut arr := [0,0,0] + mut results := []string{} + for _, mut v in arr { + v = v + 1 // v: 1 + mut vv := v // vv: 1, v: 1 + vv = vv + v // vv: 2, v: 1 + foo := {'a': v, 'b': vv} // or use new syntax foo := map{'a': v, 'b': vv}, results are the same + println(v) + println(vv) + println(foo) + results << '$v' + results << '$vv' + results << '$foo' + } + assert results[0] == '1' + assert results[1] == '2' + assert results[2] == "{'a': 1, 'b': 2}" + assert results[3] == '1' + assert results[4] == '2' + assert results[5] == "{'a': 1, 'b': 2}" + assert results[6] == '1' + assert results[7] == '2' + assert results[8] == "{'a': 1, 'b': 2}" +} + +fn foo1(mut arr [][]int) { + mut results := []int{} + for _, mut j in arr { + for _, mut k in j { + k = k + 1 // k: 1 + mut kk := k // kk: 1, k: 1 + kk = kk + k // kk: 2, k: 1 + k++ // kk: 2, k: 2 + kk++ // kk: 3, k: 2 + println(k) + println(kk) + results << k + results << kk + } + } + assert results[0] == 2 + assert results[1] == 3 + assert results[2] == 2 + assert results[3] == 3 +} + +fn test_mut_10() { + mut arr := [[0,0]] + foo1(mut arr) +} + +fn foo2(mut arr [][]int) { + mut results := []int{} + for _, mut j in arr { + for _, mut k in j { + k = k + 1 // k: 1 + mut kk := k // kk: 1, k: 1 + kk = kk + k // kk: 2, k: 1 + k-- // kk: 2, k: 2 + kk-- // kk: 3, k: 2 + println(k) + println(kk) + results << k + results << kk + } + } + assert results[0] == 0 + assert results[1] == 1 + assert results[2] == 0 + assert results[3] == 1 +} + +fn test_mut_11() { + mut arr := [[0,0]] + foo2(mut arr) +} + +fn foo3(mut arr [][]int) { + mut results := []string{} + for _, mut j in arr { + j[0] += 2 + println(j) // [2, 0] + results << '$j' + } + assert results[0] == '[2, 0]' +} + +fn test_mut_12() { + mut arr := [[0, 0]] + foo3(mut arr) +}