fix: handle method on interface type objects (#112)
Define a new Method action to detect method calls on interface types. In this case the receiver is resolved from a dynamic type rather than a static one. Handle method calls where receiver is a pointer. In typeAssert, always return an interface value with the concrete type, to fix method lookup on interface objects. Add relevant tests.
This commit is contained in:
committed by
Ludovic Fernandez
parent
80f20189b4
commit
22a6d011f4
@@ -114,12 +114,19 @@ func typeAssert(n *Node) {
|
||||
i := n.findex
|
||||
next := getExec(n.tnext)
|
||||
|
||||
if n.child[0].typ.cat == ValueT {
|
||||
switch {
|
||||
case n.child[0].typ.cat == ValueT:
|
||||
n.exec = func(f *Frame) Builtin {
|
||||
f.data[i] = value(f).Elem()
|
||||
return next
|
||||
}
|
||||
} else {
|
||||
case n.child[1].typ.cat == InterfaceT:
|
||||
n.exec = func(f *Frame) Builtin {
|
||||
v := value(f).Interface().(valueInterface)
|
||||
f.data[i] = reflect.ValueOf(valueInterface{v.node, v.value})
|
||||
return next
|
||||
}
|
||||
default:
|
||||
n.exec = func(f *Frame) Builtin {
|
||||
v := value(f).Interface().(valueInterface)
|
||||
f.data[i] = v.value
|
||||
@@ -134,7 +141,8 @@ func typeAssert2(n *Node) {
|
||||
value1 := genValue(n.anc.child[1]) // returned status
|
||||
next := getExec(n.tnext)
|
||||
|
||||
if n.child[0].typ.cat == ValueT {
|
||||
switch {
|
||||
case n.child[0].typ.cat == ValueT:
|
||||
n.exec = func(f *Frame) Builtin {
|
||||
if value(f).IsValid() && !value(f).IsNil() {
|
||||
value0(f).Set(value(f).Elem())
|
||||
@@ -142,7 +150,14 @@ func typeAssert2(n *Node) {
|
||||
value1(f).SetBool(true)
|
||||
return next
|
||||
}
|
||||
} else {
|
||||
case n.child[1].typ.cat == InterfaceT:
|
||||
n.exec = func(f *Frame) Builtin {
|
||||
v, ok := value(f).Interface().(valueInterface)
|
||||
value0(f).Set(reflect.ValueOf(valueInterface{v.node, v.value}))
|
||||
value1(f).SetBool(ok)
|
||||
return next
|
||||
}
|
||||
default:
|
||||
n.exec = func(f *Frame) Builtin {
|
||||
v, ok := value(f).Interface().(valueInterface)
|
||||
value0(f).Set(v.value)
|
||||
@@ -453,8 +468,7 @@ func call(n *Node) {
|
||||
// Compute method receiver value
|
||||
values = append(values, genValueRecv(n.child[0]))
|
||||
method = true
|
||||
}
|
||||
if n.child[0].typ.cat == InterfaceT {
|
||||
} else if n.child[0].action == Method {
|
||||
// add a place holder for interface method receiver
|
||||
values = append(values, nil)
|
||||
method = true
|
||||
@@ -529,7 +543,11 @@ func call(n *Node) {
|
||||
if v == nil {
|
||||
src = def.recv.val
|
||||
if len(def.recv.index) > 0 {
|
||||
src = src.FieldByIndex(def.recv.index)
|
||||
if src.Kind() == reflect.Ptr {
|
||||
src = src.Elem().FieldByIndex(def.recv.index)
|
||||
} else {
|
||||
src = src.FieldByIndex(def.recv.index)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
src = v(f)
|
||||
|
||||
Reference in New Issue
Block a user