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)
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
111
interp/run.go
111
interp/run.go
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user