mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
gen: fix evaluating the receiver of array methods (.map(), .filter(), etc) more than once (#7130)
This commit is contained in:
parent
f21b2b41ac
commit
52fb7033c3
@ -4767,16 +4767,14 @@ fn (mut g Gen) gen_array_map(node ast.CallExpr) {
|
|||||||
if inp_sym.kind != .array {
|
if inp_sym.kind != .array {
|
||||||
verror('map() requires an array')
|
verror('map() requires an array')
|
||||||
}
|
}
|
||||||
g.writeln('')
|
g.write('${g.typ(node.left_type)} ${tmp}_orig = ')
|
||||||
g.write('int ${tmp}_len = ')
|
|
||||||
g.expr(node.left)
|
g.expr(node.left)
|
||||||
g.writeln('.len;')
|
g.writeln(';')
|
||||||
|
g.write('int ${tmp}_len = ${tmp}_orig.len;')
|
||||||
g.writeln('$ret_typ $tmp = __new_array(0, ${tmp}_len, sizeof($ret_elem_type));')
|
g.writeln('$ret_typ $tmp = __new_array(0, ${tmp}_len, sizeof($ret_elem_type));')
|
||||||
i := g.new_tmp_var()
|
i := g.new_tmp_var()
|
||||||
g.writeln('for (int $i = 0; $i < ${tmp}_len; ++$i) {')
|
g.writeln('for (int $i = 0; $i < ${tmp}_len; ++$i) {')
|
||||||
g.write('\t$inp_elem_type it = (($inp_elem_type*) ')
|
g.write('\t$inp_elem_type it = (($inp_elem_type*) ${tmp}_orig.data)[$i];')
|
||||||
g.expr(node.left)
|
|
||||||
g.writeln('.data)[$i];')
|
|
||||||
g.write('\t$ret_elem_type ti = ')
|
g.write('\t$ret_elem_type ti = ')
|
||||||
expr := node.args[0].expr
|
expr := node.args[0].expr
|
||||||
match expr {
|
match expr {
|
||||||
@ -4919,14 +4917,13 @@ fn (mut g Gen) gen_array_filter(node ast.CallExpr) {
|
|||||||
info := sym.info as table.Array
|
info := sym.info as table.Array
|
||||||
styp := g.typ(node.return_type)
|
styp := g.typ(node.return_type)
|
||||||
elem_type_str := g.typ(info.elem_type)
|
elem_type_str := g.typ(info.elem_type)
|
||||||
g.write('\nint ${tmp}_len = ')
|
g.write('${g.typ(node.left_type)} ${tmp}_orig = ')
|
||||||
g.expr(node.left)
|
g.expr(node.left)
|
||||||
g.writeln('.len;')
|
g.writeln(';')
|
||||||
|
g.write('int ${tmp}_len = ${tmp}_orig.len;')
|
||||||
g.writeln('$styp $tmp = __new_array(0, ${tmp}_len, sizeof($elem_type_str));')
|
g.writeln('$styp $tmp = __new_array(0, ${tmp}_len, sizeof($elem_type_str));')
|
||||||
g.writeln('for (int i = 0; i < ${tmp}_len; ++i) {')
|
g.writeln('for (int i = 0; i < ${tmp}_len; ++i) {')
|
||||||
g.write(' $elem_type_str it = (($elem_type_str*) ')
|
g.writeln(' $elem_type_str it = (($elem_type_str*) ${tmp}_orig.data)[i];')
|
||||||
g.expr(node.left)
|
|
||||||
g.writeln('.data)[i];')
|
|
||||||
g.write('if (')
|
g.write('if (')
|
||||||
expr := node.args[0].expr
|
expr := node.args[0].expr
|
||||||
match expr {
|
match expr {
|
||||||
|
20
vlib/v/tests/array_methods_test.v
Normal file
20
vlib/v/tests/array_methods_test.v
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
struct Counter {
|
||||||
|
mut:
|
||||||
|
val int
|
||||||
|
}
|
||||||
|
|
||||||
|
// if this is called more than once, the test'll fail
|
||||||
|
fn (mut c Counter) new_arr(msg string) []int {
|
||||||
|
if c.val > 0 { panic(msg) }
|
||||||
|
c.val++
|
||||||
|
return [1, 3, 2]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_array_eval_count() {
|
||||||
|
// `new_arr()` should only be evaluated once, not on every iteration
|
||||||
|
mut a1 := Counter{}
|
||||||
|
assert a1.new_arr('map() failed').map(it * 2) == [2, 6, 4]
|
||||||
|
|
||||||
|
mut a2 := Counter{}
|
||||||
|
assert a2.new_arr('filter() failed').filter(it < 3) == [1, 2]
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user