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:
Marc Vertes
2019-03-04 18:51:48 +01:00
committed by Ludovic Fernandez
parent 80f20189b4
commit 22a6d011f4
4 changed files with 61 additions and 7 deletions

View File

@@ -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)