fix: handle interface values in map and arrays

This commit is contained in:
Marc Vertes
2020-03-03 18:32:04 +01:00
committed by GitHub
parent 94e0b582ea
commit cfb73445a2
9 changed files with 181 additions and 32 deletions

12
_test/interface20.go Normal file
View File

@@ -0,0 +1,12 @@
package main
import "fmt"
func main() {
var a interface{}
a = string("A")
fmt.Println(a)
}
// Output:
// A

12
_test/interface21.go Normal file
View File

@@ -0,0 +1,12 @@
package main
import "fmt"
func main() {
s := make([]interface{}, 1)
s[0] = 1
fmt.Println(s[0])
}
// Output:
// 1

12
_test/interface22.go Normal file
View File

@@ -0,0 +1,12 @@
package main
import "fmt"
func main() {
s := make([]interface{}, 0)
s = append(s, 1)
fmt.Println(s[0])
}
// Output:
// 1

12
_test/interface23.go Normal file
View File

@@ -0,0 +1,12 @@
package main
import "fmt"
func main() {
m := make(map[string]interface{})
m["A"] = string("A")
fmt.Println(m["A"])
}
// Output:
// A

11
_test/interface24.go Normal file
View File

@@ -0,0 +1,11 @@
package main
import "fmt"
func main() {
m := make(map[string]interface{})
fmt.Println(m["B"])
}
// Output:
// <nil>

14
_test/interface25.go Normal file
View File

@@ -0,0 +1,14 @@
package main
import "fmt"
func main() {
m := make(map[string]interface{})
m["A"] = 1
for _, v := range m {
fmt.Println(v)
}
}
// Output:
// 1

14
_test/interface26.go Normal file
View File

@@ -0,0 +1,14 @@
package main
import "fmt"
func main() {
s := make([]interface{}, 0)
s = append(s, 1)
for _, v := range s {
fmt.Println(v)
}
}
// Output:
// 1

View File

@@ -464,7 +464,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
err = n.cfgErrorf("illegal operand types for '%v' operator", n.action)
}
default:
// Detect invalid float truncate
// Detect invalid float truncate.
if isInt(t0) && isFloat(t1) {
err = src.cfgErrorf("invalid float truncate")
return
@@ -475,7 +475,8 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
// Propagate type
// TODO: Check that existing destination type matches source type
switch {
case n.action == aAssign && src.action == aCall:
case n.action == aAssign && src.action == aCall && dest.typ.cat != interfaceT:
// Call action may perform the assignment directly.
n.gen = nop
src.level = level
src.findex = dest.findex
@@ -483,7 +484,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
src.typ = dest.typ
}
case n.action == aAssign && src.action == aRecv:
// Assign by reading from a receiving channel
// Assign by reading from a receiving channel.
n.gen = nop
src.findex = dest.findex // Set recv address to LHS
dest.typ = src.typ
@@ -492,16 +493,16 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
src.findex = dest.findex
src.level = level
case src.kind == basicLit:
// TODO: perform constant folding and propagation here
// TODO: perform constant folding and propagation here.
switch {
case dest.typ.cat == interfaceT:
case isComplex(dest.typ.TypeOf()):
// value set in genValue
// Value set in genValue.
case !src.rval.IsValid():
// Assign to nil
// Assign to nil.
src.rval = reflect.New(dest.typ.TypeOf()).Elem()
default:
// Convert literal value to destination type
// Convert literal value to destination type.
src.rval = src.rval.Convert(dest.typ.TypeOf())
src.typ = dest.typ
}

View File

@@ -1025,12 +1025,13 @@ func getIndexMap(n *node) {
dest := genValue(n)
value0 := genValue(n.child[0]) // map
tnext := getExec(n.tnext)
z := reflect.New(n.child[0].typ.TypeOf().Elem()).Elem()
z := reflect.New(n.child[0].typ.frameType().Elem()).Elem()
if n.child[1].rval.IsValid() { // constant map index
mi := n.child[1].rval
if n.fnext != nil {
switch {
case n.fnext != nil:
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
if v := value0(f).MapIndex(mi); v.IsValid() && v.Bool() {
@@ -1040,7 +1041,17 @@ func getIndexMap(n *node) {
dest(f).Set(z)
return fnext
}
} else {
case n.typ.cat == interfaceT:
z = reflect.New(n.child[0].typ.val.frameType()).Elem()
n.exec = func(f *frame) bltn {
if v := value0(f).MapIndex(mi); v.IsValid() {
dest(f).Set(v.Elem())
} else {
dest(f).Set(z)
}
return tnext
}
default:
n.exec = func(f *frame) bltn {
if v := value0(f).MapIndex(mi); v.IsValid() {
dest(f).Set(v)
@@ -1053,7 +1064,8 @@ func getIndexMap(n *node) {
} else {
value1 := genValue(n.child[1]) // map index
if n.fnext != nil {
switch {
case n.fnext != nil:
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
if v := value0(f).MapIndex(value1(f)); v.IsValid() && v.Bool() {
@@ -1063,7 +1075,17 @@ func getIndexMap(n *node) {
dest(f).Set(z)
return fnext
}
} else {
case n.typ.cat == interfaceT:
z = reflect.New(n.child[0].typ.val.frameType()).Elem()
n.exec = func(f *frame) bltn {
if v := value0(f).MapIndex(value1(f)); v.IsValid() {
dest(f).Set(v.Elem())
} else {
dest(f).Set(z)
}
return tnext
}
default:
n.exec = func(f *frame) bltn {
if v := value0(f).MapIndex(value1(f)); v.IsValid() {
dest(f).Set(v)
@@ -1082,26 +1104,49 @@ func getIndexMap2(n *node) {
value0 := genValue(n.child[0]) // map
value2 := genValue(n.anc.child[1]) // status
next := getExec(n.tnext)
typ := n.anc.child[0].typ
if n.child[1].rval.IsValid() { // constant map index
mi := n.child[1].rval
n.exec = func(f *frame) bltn {
v := value0(f).MapIndex(mi)
if v.IsValid() {
dest(f).Set(v)
if typ.cat == interfaceT {
n.exec = func(f *frame) bltn {
v := value0(f).MapIndex(mi)
if v.IsValid() {
dest(f).Set(v.Elem())
}
value2(f).SetBool(v.IsValid())
return next
}
} else {
n.exec = func(f *frame) bltn {
v := value0(f).MapIndex(mi)
if v.IsValid() {
dest(f).Set(v)
}
value2(f).SetBool(v.IsValid())
return next
}
value2(f).SetBool(v.IsValid())
return next
}
} else {
value1 := genValue(n.child[1]) // map index
n.exec = func(f *frame) bltn {
v := value0(f).MapIndex(value1(f))
if v.IsValid() {
dest(f).Set(v)
if typ.cat == interfaceT {
n.exec = func(f *frame) bltn {
v := value0(f).MapIndex(value1(f))
if v.IsValid() {
dest(f).Set(v.Elem())
}
value2(f).SetBool(v.IsValid())
return next
}
} else {
n.exec = func(f *frame) bltn {
v := value0(f).MapIndex(value1(f))
if v.IsValid() {
dest(f).Set(v)
}
value2(f).SetBool(v.IsValid())
return next
}
value2(f).SetBool(v.IsValid())
return next
}
}
}
@@ -1785,14 +1830,26 @@ func rangeMap(n *node) {
if len(n.child) == 4 {
index1 := n.child[1].findex // map value location in frame
value = genValue(n.child[2]) // map
n.exec = func(f *frame) bltn {
iter := f.data[index2].Interface().(*reflect.MapIter)
if !iter.Next() {
return fnext
if n.child[1].typ.cat == interfaceT {
n.exec = func(f *frame) bltn {
iter := f.data[index2].Interface().(*reflect.MapIter)
if !iter.Next() {
return fnext
}
f.data[index0].Set(iter.Key())
f.data[index1].Set(iter.Value().Elem())
return tnext
}
} else {
n.exec = func(f *frame) bltn {
iter := f.data[index2].Interface().(*reflect.MapIter)
if !iter.Next() {
return fnext
}
f.data[index0].Set(iter.Key())
f.data[index1].Set(iter.Value())
return tnext
}
f.data[index0].Set(iter.Key())
f.data[index1].Set(iter.Value())
return tnext
}
} else {
value = genValue(n.child[1]) // map
@@ -1960,6 +2017,8 @@ func _append(n *node) {
values := make([]func(*frame) reflect.Value, l)
for i, arg := range args {
switch {
case n.typ.val.cat == interfaceT:
values[i] = genValueInterface(arg)
case isRecursiveStruct(n.typ.val, n.typ.val.rtype):
values[i] = genValueInterfacePtr(arg)
case arg.typ.untyped:
@@ -1980,6 +2039,8 @@ func _append(n *node) {
} else {
var value0 func(*frame) reflect.Value
switch {
case n.typ.val.cat == interfaceT:
value0 = genValueInterface(n.child[2])
case isRecursiveStruct(n.typ.val, n.typ.val.rtype):
value0 = genValueInterfacePtr(n.child[2])
case n.child[2].typ.untyped:
@@ -2113,7 +2174,7 @@ func _new(n *node) {
func _make(n *node) {
dest := genValue(n)
next := getExec(n.tnext)
typ := n.child[1].typ.TypeOf()
typ := n.child[1].typ.frameType()
switch typ.Kind() {
case reflect.Array, reflect.Slice: