From bb2921b42f496059a62391fb98fb890715d92e23 Mon Sep 17 00:00:00 2001 From: Dan Kortschak Date: Tue, 1 Oct 2019 06:14:04 +0930 Subject: [PATCH] interp: fix range expression handling --- _test/range0.go | 14 ++++++++++++++ _test/range1.go | 14 ++++++++++++++ _test/range2.go | 14 ++++++++++++++ interp/cfg.go | 4 ++++ interp/run.go | 13 +++++++------ interp/value.go | 16 ++++++++++++++++ 6 files changed, 69 insertions(+), 6 deletions(-) create mode 100644 _test/range0.go create mode 100644 _test/range1.go create mode 100644 _test/range2.go diff --git a/_test/range0.go b/_test/range0.go new file mode 100644 index 000000000..c6e780405 --- /dev/null +++ b/_test/range0.go @@ -0,0 +1,14 @@ +package main + +import "fmt" + +func main() { + v := []int{1, 2, 3} + for i := range v { + v = append(v, i) + } + fmt.Println(v) +} + +// Output: +// [1 2 3 0 1 2] diff --git a/_test/range1.go b/_test/range1.go new file mode 100644 index 000000000..68badeee7 --- /dev/null +++ b/_test/range1.go @@ -0,0 +1,14 @@ +package main + +import "fmt" + +func main() { + a := [...]int{2, 1, 0} + for _, v := range a { + a[v] = v + } + fmt.Println(a) +} + +// Output: +// [0 1 2] diff --git a/_test/range2.go b/_test/range2.go new file mode 100644 index 000000000..2680ba40c --- /dev/null +++ b/_test/range2.go @@ -0,0 +1,14 @@ +package main + +import "fmt" + +func main() { + a := [...]int{2, 1, 0} + for _, v := range &a { + a[v] = v + } + fmt.Println(a) +} + +// Output: +// [2 1 2] diff --git a/interp/cfg.go b/interp/cfg.go index be1e43e9e..e7ae45dc8 100644 --- a/interp/cfg.go +++ b/interp/cfg.go @@ -77,9 +77,11 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) { ktyp = &itype{cat: valueT, rtype: typ.Key()} vtyp = &itype{cat: valueT, rtype: typ.Elem()} case reflect.String: + sc.add(sc.getType("int")) // Add a dummy type to store array shallow copy for range ktyp = sc.getType("int") vtyp = sc.getType("rune") case reflect.Array, reflect.Slice: + sc.add(sc.getType("int")) // Add a dummy type to store array shallow copy for range ktyp = sc.getType("int") vtyp = &itype{cat: valueT, rtype: typ.Elem()} } @@ -96,9 +98,11 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) { vtyp = vtyp.val } case stringT: + sc.add(sc.getType("int")) // Add a dummy type to store array shallow copy for range ktyp = sc.getType("int") vtyp = sc.getType("rune") case arrayT, variadicT: + sc.add(sc.getType("int")) // Add a dummy type to store array shallow copy for range ktyp = sc.getType("int") vtyp = o.typ.val } diff --git a/interp/run.go b/interp/run.go index c1440ce4a..7fedfac5e 100644 --- a/interp/run.go +++ b/interp/run.go @@ -1534,6 +1534,7 @@ var rat = reflect.ValueOf((*[]rune)(nil)).Type().Elem() // runes array type func _range(n *node) { index0 := n.child[0].findex // array index location in frame + index2 := index0 - 1 // shallow array for range, always just behind index0 fnext := getExec(n.fnext) tnext := getExec(n.tnext) @@ -1544,10 +1545,10 @@ func _range(n *node) { if isString(an.typ.TypeOf()) { value = genValueAs(an, rat) // range on string iterates over runes } else { - value = genValueArray(an) + value = genValueRangeArray(an) } n.exec = func(f *frame) bltn { - a := value(f) + a := f.data[index2] v0 := f.data[index0] v0.SetInt(v0.Int() + 1) i := int(v0.Int()) @@ -1562,13 +1563,12 @@ func _range(n *node) { if isString(an.typ.TypeOf()) { value = genValueAs(an, rat) // range on string iterates over runes } else { - value = genValueArray(an) + value = genValueRangeArray(an) } n.exec = func(f *frame) bltn { - a := value(f) v0 := f.data[index0] v0.SetInt(v0.Int() + 1) - if int(v0.Int()) >= a.Len() { + if int(v0.Int()) >= f.data[index2].Len() { return fnext } return tnext @@ -1578,7 +1578,8 @@ func _range(n *node) { // Init sequence next := n.exec n.child[0].exec = func(f *frame) bltn { - f.data[index0].SetInt(-1) + f.data[index2] = value(f) // set array shallow copy for range + f.data[index0].SetInt(-1) // assing index value return next } } diff --git a/interp/value.go b/interp/value.go index 72fae603f..417fdd4e9 100644 --- a/interp/value.go +++ b/interp/value.go @@ -118,6 +118,22 @@ func genValueArray(n *node) func(*frame) reflect.Value { return value } +func genValueRangeArray(n *node) func(*frame) reflect.Value { + value := genValue(n) + // dereference array pointer, to support array operations on array pointer + if n.typ.TypeOf().Kind() == reflect.Ptr { + return func(f *frame) reflect.Value { + return value(f).Elem() + } + } + return func(f *frame) reflect.Value { + // This is necessary to prevent changes in the returned + // reflect.Value being reflected back to the value used + // for the range expression. + return reflect.ValueOf(value(f).Interface()) + } +} + func genValueInterfacePtr(n *node) func(*frame) reflect.Value { value := genValue(n) it := reflect.TypeOf((*interface{})(nil)).Elem()