interp: fix handling map of interfaces
Map handling builtins getIndexMap and rangeMap had some leftover code of previous way of emulating interfaces, which was modified following changes in #1017. Specific code for interfaceT is removed, as not necessary anymore. Map builtins are now simplified and more robust. Fixes #1189.
This commit is contained in:
31
_test/issue-1189.go
Normal file
31
_test/issue-1189.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package main
|
||||
|
||||
type I interface {
|
||||
Foo() int
|
||||
}
|
||||
|
||||
type S1 struct {
|
||||
i int
|
||||
}
|
||||
|
||||
func (s S1) Foo() int { return s.i }
|
||||
|
||||
type S2 struct{}
|
||||
|
||||
func (s *S2) Foo() int { return 42 }
|
||||
|
||||
func main() {
|
||||
Is := map[string]I{
|
||||
"foo": S1{21},
|
||||
"bar": &S2{},
|
||||
}
|
||||
n := 0
|
||||
for _, s := range Is {
|
||||
n += s.Foo()
|
||||
}
|
||||
bar := "bar"
|
||||
println(n, Is["foo"].Foo(), Is[bar].Foo())
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 63 21 42
|
||||
@@ -1622,27 +1622,6 @@ func getIndexMap(n *node) {
|
||||
dest(f).Set(z)
|
||||
return fnext
|
||||
}
|
||||
case isInterfaceSrc(n.typ):
|
||||
z = reflect.New(n.child[0].typ.val.frameType()).Elem()
|
||||
n.exec = func(f *frame) bltn {
|
||||
v := value0(f).MapIndex(mi)
|
||||
if !v.IsValid() {
|
||||
dest(f).Set(z)
|
||||
return tnext
|
||||
}
|
||||
e := v.Elem()
|
||||
if len(n.typ.field) == 0 {
|
||||
// e is empty interface, do not wrap
|
||||
dest(f).Set(e)
|
||||
return tnext
|
||||
}
|
||||
if e.Type().AssignableTo(valueInterfaceType) {
|
||||
dest(f).Set(e)
|
||||
return tnext
|
||||
}
|
||||
dest(f).Set(reflect.ValueOf(valueInterface{n, e}))
|
||||
return tnext
|
||||
}
|
||||
default:
|
||||
n.exec = func(f *frame) bltn {
|
||||
if v := value0(f).MapIndex(mi); v.IsValid() {
|
||||
@@ -1667,20 +1646,6 @@ func getIndexMap(n *node) {
|
||||
dest(f).Set(z)
|
||||
return fnext
|
||||
}
|
||||
case isInterfaceSrc(n.typ):
|
||||
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() {
|
||||
if e := v.Elem(); e.Type().AssignableTo(valueInterfaceType) {
|
||||
dest(f).Set(e)
|
||||
} else {
|
||||
dest(f).Set(reflect.ValueOf(valueInterface{n, e}))
|
||||
}
|
||||
} else {
|
||||
dest(f).Set(z)
|
||||
}
|
||||
return tnext
|
||||
}
|
||||
default:
|
||||
n.exec = func(f *frame) bltn {
|
||||
if v := value0(f).MapIndex(value1(f)); v.IsValid() {
|
||||
@@ -2729,47 +2694,14 @@ 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
|
||||
if isInterfaceSrc(n.child[1].typ) {
|
||||
if len(n.child[1].typ.field) > 0 {
|
||||
n.exec = func(f *frame) bltn {
|
||||
iter := f.data[index2].Interface().(*reflect.MapIter)
|
||||
if !iter.Next() {
|
||||
return fnext
|
||||
}
|
||||
f.data[index0].Set(iter.Key())
|
||||
if e := iter.Value().Elem(); e.Type().AssignableTo(valueInterfaceType) {
|
||||
f.data[index1].Set(e)
|
||||
} else {
|
||||
f.data[index1].Set(reflect.ValueOf(valueInterface{n, e}))
|
||||
}
|
||||
return tnext
|
||||
}
|
||||
} else {
|
||||
// empty interface, do not wrap
|
||||
n.exec = func(f *frame) bltn {
|
||||
iter := f.data[index2].Interface().(*reflect.MapIter)
|
||||
if !iter.Next() {
|
||||
return fnext
|
||||
}
|
||||
f.data[index0].Set(iter.Key())
|
||||
if iter.Value().Elem().IsValid() {
|
||||
f.data[index1].Set(iter.Value().Elem())
|
||||
} else {
|
||||
f.data[index1].Set(reflect.New(interf).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
|
||||
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
|
||||
}
|
||||
} else {
|
||||
value = genValue(n.child[1]) // map
|
||||
|
||||
Reference in New Issue
Block a user