fix: handle interface values in map and arrays
This commit is contained in:
12
_test/interface20.go
Normal file
12
_test/interface20.go
Normal 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
12
_test/interface21.go
Normal 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
12
_test/interface22.go
Normal 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
12
_test/interface23.go
Normal 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
11
_test/interface24.go
Normal 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
14
_test/interface25.go
Normal 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
14
_test/interface26.go
Normal 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
|
||||||
@@ -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)
|
err = n.cfgErrorf("illegal operand types for '%v' operator", n.action)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
// Detect invalid float truncate
|
// Detect invalid float truncate.
|
||||||
if isInt(t0) && isFloat(t1) {
|
if isInt(t0) && isFloat(t1) {
|
||||||
err = src.cfgErrorf("invalid float truncate")
|
err = src.cfgErrorf("invalid float truncate")
|
||||||
return
|
return
|
||||||
@@ -475,7 +475,8 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
|||||||
// Propagate type
|
// Propagate type
|
||||||
// TODO: Check that existing destination type matches source type
|
// TODO: Check that existing destination type matches source type
|
||||||
switch {
|
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
|
n.gen = nop
|
||||||
src.level = level
|
src.level = level
|
||||||
src.findex = dest.findex
|
src.findex = dest.findex
|
||||||
@@ -483,7 +484,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
|||||||
src.typ = dest.typ
|
src.typ = dest.typ
|
||||||
}
|
}
|
||||||
case n.action == aAssign && src.action == aRecv:
|
case n.action == aAssign && src.action == aRecv:
|
||||||
// Assign by reading from a receiving channel
|
// Assign by reading from a receiving channel.
|
||||||
n.gen = nop
|
n.gen = nop
|
||||||
src.findex = dest.findex // Set recv address to LHS
|
src.findex = dest.findex // Set recv address to LHS
|
||||||
dest.typ = src.typ
|
dest.typ = src.typ
|
||||||
@@ -492,16 +493,16 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
|||||||
src.findex = dest.findex
|
src.findex = dest.findex
|
||||||
src.level = level
|
src.level = level
|
||||||
case src.kind == basicLit:
|
case src.kind == basicLit:
|
||||||
// TODO: perform constant folding and propagation here
|
// TODO: perform constant folding and propagation here.
|
||||||
switch {
|
switch {
|
||||||
case dest.typ.cat == interfaceT:
|
case dest.typ.cat == interfaceT:
|
||||||
case isComplex(dest.typ.TypeOf()):
|
case isComplex(dest.typ.TypeOf()):
|
||||||
// value set in genValue
|
// Value set in genValue.
|
||||||
case !src.rval.IsValid():
|
case !src.rval.IsValid():
|
||||||
// Assign to nil
|
// Assign to nil.
|
||||||
src.rval = reflect.New(dest.typ.TypeOf()).Elem()
|
src.rval = reflect.New(dest.typ.TypeOf()).Elem()
|
||||||
default:
|
default:
|
||||||
// Convert literal value to destination type
|
// Convert literal value to destination type.
|
||||||
src.rval = src.rval.Convert(dest.typ.TypeOf())
|
src.rval = src.rval.Convert(dest.typ.TypeOf())
|
||||||
src.typ = dest.typ
|
src.typ = dest.typ
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1025,12 +1025,13 @@ func getIndexMap(n *node) {
|
|||||||
dest := genValue(n)
|
dest := genValue(n)
|
||||||
value0 := genValue(n.child[0]) // map
|
value0 := genValue(n.child[0]) // map
|
||||||
tnext := getExec(n.tnext)
|
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
|
if n.child[1].rval.IsValid() { // constant map index
|
||||||
mi := n.child[1].rval
|
mi := n.child[1].rval
|
||||||
|
|
||||||
if n.fnext != nil {
|
switch {
|
||||||
|
case n.fnext != nil:
|
||||||
fnext := getExec(n.fnext)
|
fnext := getExec(n.fnext)
|
||||||
n.exec = func(f *frame) bltn {
|
n.exec = func(f *frame) bltn {
|
||||||
if v := value0(f).MapIndex(mi); v.IsValid() && v.Bool() {
|
if v := value0(f).MapIndex(mi); v.IsValid() && v.Bool() {
|
||||||
@@ -1040,7 +1041,17 @@ func getIndexMap(n *node) {
|
|||||||
dest(f).Set(z)
|
dest(f).Set(z)
|
||||||
return fnext
|
return fnext
|
||||||
}
|
}
|
||||||
|
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 {
|
} else {
|
||||||
|
dest(f).Set(z)
|
||||||
|
}
|
||||||
|
return tnext
|
||||||
|
}
|
||||||
|
default:
|
||||||
n.exec = func(f *frame) bltn {
|
n.exec = func(f *frame) bltn {
|
||||||
if v := value0(f).MapIndex(mi); v.IsValid() {
|
if v := value0(f).MapIndex(mi); v.IsValid() {
|
||||||
dest(f).Set(v)
|
dest(f).Set(v)
|
||||||
@@ -1053,7 +1064,8 @@ func getIndexMap(n *node) {
|
|||||||
} else {
|
} else {
|
||||||
value1 := genValue(n.child[1]) // map index
|
value1 := genValue(n.child[1]) // map index
|
||||||
|
|
||||||
if n.fnext != nil {
|
switch {
|
||||||
|
case n.fnext != nil:
|
||||||
fnext := getExec(n.fnext)
|
fnext := getExec(n.fnext)
|
||||||
n.exec = func(f *frame) bltn {
|
n.exec = func(f *frame) bltn {
|
||||||
if v := value0(f).MapIndex(value1(f)); v.IsValid() && v.Bool() {
|
if v := value0(f).MapIndex(value1(f)); v.IsValid() && v.Bool() {
|
||||||
@@ -1063,7 +1075,17 @@ func getIndexMap(n *node) {
|
|||||||
dest(f).Set(z)
|
dest(f).Set(z)
|
||||||
return fnext
|
return fnext
|
||||||
}
|
}
|
||||||
|
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 {
|
} else {
|
||||||
|
dest(f).Set(z)
|
||||||
|
}
|
||||||
|
return tnext
|
||||||
|
}
|
||||||
|
default:
|
||||||
n.exec = func(f *frame) bltn {
|
n.exec = func(f *frame) bltn {
|
||||||
if v := value0(f).MapIndex(value1(f)); v.IsValid() {
|
if v := value0(f).MapIndex(value1(f)); v.IsValid() {
|
||||||
dest(f).Set(v)
|
dest(f).Set(v)
|
||||||
@@ -1082,9 +1104,20 @@ func getIndexMap2(n *node) {
|
|||||||
value0 := genValue(n.child[0]) // map
|
value0 := genValue(n.child[0]) // map
|
||||||
value2 := genValue(n.anc.child[1]) // status
|
value2 := genValue(n.anc.child[1]) // status
|
||||||
next := getExec(n.tnext)
|
next := getExec(n.tnext)
|
||||||
|
typ := n.anc.child[0].typ
|
||||||
|
|
||||||
if n.child[1].rval.IsValid() { // constant map index
|
if n.child[1].rval.IsValid() { // constant map index
|
||||||
mi := n.child[1].rval
|
mi := n.child[1].rval
|
||||||
|
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 {
|
n.exec = func(f *frame) bltn {
|
||||||
v := value0(f).MapIndex(mi)
|
v := value0(f).MapIndex(mi)
|
||||||
if v.IsValid() {
|
if v.IsValid() {
|
||||||
@@ -1093,8 +1126,19 @@ func getIndexMap2(n *node) {
|
|||||||
value2(f).SetBool(v.IsValid())
|
value2(f).SetBool(v.IsValid())
|
||||||
return next
|
return next
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
value1 := genValue(n.child[1]) // map index
|
value1 := genValue(n.child[1]) // map index
|
||||||
|
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 {
|
n.exec = func(f *frame) bltn {
|
||||||
v := value0(f).MapIndex(value1(f))
|
v := value0(f).MapIndex(value1(f))
|
||||||
if v.IsValid() {
|
if v.IsValid() {
|
||||||
@@ -1104,6 +1148,7 @@ func getIndexMap2(n *node) {
|
|||||||
return next
|
return next
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getFunc(n *node) {
|
func getFunc(n *node) {
|
||||||
@@ -1785,6 +1830,17 @@ func rangeMap(n *node) {
|
|||||||
if len(n.child) == 4 {
|
if len(n.child) == 4 {
|
||||||
index1 := n.child[1].findex // map value location in frame
|
index1 := n.child[1].findex // map value location in frame
|
||||||
value = genValue(n.child[2]) // map
|
value = genValue(n.child[2]) // map
|
||||||
|
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 {
|
n.exec = func(f *frame) bltn {
|
||||||
iter := f.data[index2].Interface().(*reflect.MapIter)
|
iter := f.data[index2].Interface().(*reflect.MapIter)
|
||||||
if !iter.Next() {
|
if !iter.Next() {
|
||||||
@@ -1794,6 +1850,7 @@ func rangeMap(n *node) {
|
|||||||
f.data[index1].Set(iter.Value())
|
f.data[index1].Set(iter.Value())
|
||||||
return tnext
|
return tnext
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
value = genValue(n.child[1]) // map
|
value = genValue(n.child[1]) // map
|
||||||
n.exec = func(f *frame) bltn {
|
n.exec = func(f *frame) bltn {
|
||||||
@@ -1960,6 +2017,8 @@ func _append(n *node) {
|
|||||||
values := make([]func(*frame) reflect.Value, l)
|
values := make([]func(*frame) reflect.Value, l)
|
||||||
for i, arg := range args {
|
for i, arg := range args {
|
||||||
switch {
|
switch {
|
||||||
|
case n.typ.val.cat == interfaceT:
|
||||||
|
values[i] = genValueInterface(arg)
|
||||||
case isRecursiveStruct(n.typ.val, n.typ.val.rtype):
|
case isRecursiveStruct(n.typ.val, n.typ.val.rtype):
|
||||||
values[i] = genValueInterfacePtr(arg)
|
values[i] = genValueInterfacePtr(arg)
|
||||||
case arg.typ.untyped:
|
case arg.typ.untyped:
|
||||||
@@ -1980,6 +2039,8 @@ func _append(n *node) {
|
|||||||
} else {
|
} else {
|
||||||
var value0 func(*frame) reflect.Value
|
var value0 func(*frame) reflect.Value
|
||||||
switch {
|
switch {
|
||||||
|
case n.typ.val.cat == interfaceT:
|
||||||
|
value0 = genValueInterface(n.child[2])
|
||||||
case isRecursiveStruct(n.typ.val, n.typ.val.rtype):
|
case isRecursiveStruct(n.typ.val, n.typ.val.rtype):
|
||||||
value0 = genValueInterfacePtr(n.child[2])
|
value0 = genValueInterfacePtr(n.child[2])
|
||||||
case n.child[2].typ.untyped:
|
case n.child[2].typ.untyped:
|
||||||
@@ -2113,7 +2174,7 @@ func _new(n *node) {
|
|||||||
func _make(n *node) {
|
func _make(n *node) {
|
||||||
dest := genValue(n)
|
dest := genValue(n)
|
||||||
next := getExec(n.tnext)
|
next := getExec(n.tnext)
|
||||||
typ := n.child[1].typ.TypeOf()
|
typ := n.child[1].typ.frameType()
|
||||||
|
|
||||||
switch typ.Kind() {
|
switch typ.Kind() {
|
||||||
case reflect.Array, reflect.Slice:
|
case reflect.Array, reflect.Slice:
|
||||||
|
|||||||
Reference in New Issue
Block a user