interp: fix handling interface types in wrapped functions
The interpreter interface type was replaced by a reflect.Value in objects passed or return to function wrappers, losing the ability to retrieve methods. The valueInterface is now preserved, and correctly accessed if wrapped multiple times. Fixes #977.
This commit is contained in:
32
_test/interface47.go
Normal file
32
_test/interface47.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package main
|
||||
|
||||
type Doer interface {
|
||||
Do() error
|
||||
}
|
||||
|
||||
type T struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
func (t *T) Do() error { println("in do"); return nil }
|
||||
|
||||
func f() (Doer, error) { return &T{"truc"}, nil }
|
||||
|
||||
type Ev struct {
|
||||
doer func() (Doer, error)
|
||||
}
|
||||
|
||||
func (e *Ev) do() {
|
||||
d, _ := e.doer()
|
||||
d.Do()
|
||||
}
|
||||
|
||||
func main() {
|
||||
e := &Ev{f}
|
||||
println(e != nil)
|
||||
e.do()
|
||||
}
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// in do
|
||||
@@ -1878,8 +1878,15 @@ func compDefineX(sc *scope, n *node) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for funtype.cat == valueT && funtype.val != nil {
|
||||
// Retrieve original interpreter type from a wrapped function.
|
||||
// Struct fields of function types are always wrapped in valueT to ensure
|
||||
// their possible use in runtime. In that case, the val field retains the
|
||||
// original interpreter type, which is used now.
|
||||
funtype = funtype.val
|
||||
}
|
||||
if funtype.cat == valueT {
|
||||
// Handle functions imported from runtime
|
||||
// Handle functions imported from runtime.
|
||||
for i := 0; i < funtype.rtype.NumOut(); i++ {
|
||||
types = append(types, &itype{cat: valueT, rtype: funtype.rtype.Out(i)})
|
||||
}
|
||||
|
||||
@@ -386,6 +386,7 @@ func typeAssert(n *node, withResult, withOk bool) {
|
||||
}
|
||||
return next
|
||||
}
|
||||
v = valueInterfaceValue(v)
|
||||
ok = canAssertTypes(v.Type(), rtype)
|
||||
if !ok {
|
||||
if !withOk {
|
||||
@@ -887,11 +888,6 @@ func genFunctionWrapper(n *node) func(*frame) reflect.Value {
|
||||
if v, ok := r.Interface().(*node); ok {
|
||||
result[i] = genFunctionWrapper(v)(f)
|
||||
}
|
||||
if def.typ.ret[i].cat == interfaceT {
|
||||
x := result[i].Interface().(valueInterface).value
|
||||
result[i] = reflect.New(reflect.TypeOf((*interface{})(nil)).Elem()).Elem()
|
||||
result[i].Set(x)
|
||||
}
|
||||
}
|
||||
return result
|
||||
})
|
||||
@@ -1271,13 +1267,13 @@ func callBin(n *node) {
|
||||
numOut := c.child[0].typ.rtype.NumOut()
|
||||
for j := 0; j < numOut; j++ {
|
||||
ind := c.findex + j
|
||||
values = append(values, func(f *frame) reflect.Value { return f.data[ind] })
|
||||
values = append(values, func(f *frame) reflect.Value { return valueInterfaceValue(f.data[ind]) })
|
||||
}
|
||||
case isRegularCall(c):
|
||||
// Handle nested function calls: pass returned values as arguments
|
||||
for j := range c.child[0].typ.ret {
|
||||
ind := c.findex + j
|
||||
values = append(values, func(f *frame) reflect.Value { return f.data[ind] })
|
||||
values = append(values, func(f *frame) reflect.Value { return valueInterfaceValue(f.data[ind]) })
|
||||
}
|
||||
default:
|
||||
if c.kind == basicLit || c.rval.IsValid() {
|
||||
@@ -1371,7 +1367,11 @@ func callBin(n *node) {
|
||||
for i := range rvalues {
|
||||
c := n.anc.child[i]
|
||||
if c.ident != "_" {
|
||||
rvalues[i] = genValue(c)
|
||||
if c.typ.cat == interfaceT {
|
||||
rvalues[i] = genValueInterfaceValue(c)
|
||||
} else {
|
||||
rvalues[i] = genValue(c)
|
||||
}
|
||||
}
|
||||
}
|
||||
n.exec = func(f *frame) bltn {
|
||||
@@ -1714,6 +1714,13 @@ func getMethodByName(n *node) {
|
||||
|
||||
n.exec = func(f *frame) bltn {
|
||||
val := value0(f).Interface().(valueInterface)
|
||||
for {
|
||||
v, ok := val.value.Interface().(valueInterface)
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
val = v
|
||||
}
|
||||
typ := val.node.typ
|
||||
if typ.node == nil && typ.cat == valueT {
|
||||
// happens with a var of empty interface type, that has value of concrete type
|
||||
|
||||
@@ -297,6 +297,17 @@ func genValueOutput(n *node, t reflect.Type) func(*frame) reflect.Value {
|
||||
return value
|
||||
}
|
||||
|
||||
func valueInterfaceValue(v reflect.Value) reflect.Value {
|
||||
for {
|
||||
vv, ok := v.Interface().(valueInterface)
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
v = vv.value
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func genValueInterfaceValue(n *node) func(*frame) reflect.Value {
|
||||
value := genValue(n)
|
||||
|
||||
@@ -307,7 +318,7 @@ func genValueInterfaceValue(n *node) func(*frame) reflect.Value {
|
||||
v.Set(zeroInterfaceValue())
|
||||
v = value(f)
|
||||
}
|
||||
return v.Interface().(valueInterface).value
|
||||
return valueInterfaceValue(v)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user