interp: fix range expression handling

This commit is contained in:
Dan Kortschak
2019-10-01 06:14:04 +09:30
committed by Traefiker Bot
parent 2c2b471cb9
commit bb2921b42f
6 changed files with 69 additions and 6 deletions

14
_test/range0.go Normal file
View File

@@ -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]

14
_test/range1.go Normal file
View File

@@ -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]

14
_test/range2.go Normal file
View File

@@ -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]

View File

@@ -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
}

View File

@@ -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
}
}

View File

@@ -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()