Skip to content

Commit

Permalink
interp: improve method resolution for embedded interfaces
Browse files Browse the repository at this point in the history
The function `getMethodByName()` is now able to look for
embedded `valueInterface` field for matching methods in interface
struct fields.
    
Fixes #1439 and #1427.
  • Loading branch information
mvertes committed Aug 17, 2022
1 parent b2aa636 commit ab869c8
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 0 deletions.
25 changes: 25 additions & 0 deletions _test/issue-1439.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package main

type Transformer interface {
Reset()
}

type Encoder struct {
Transformer
}

type nop struct{}

func (nop) Reset() { println("Reset") }

func f(e Transformer) {
e.Reset()
}

func main() {
e := Encoder{Transformer: nop{}}
f(e)
}

// Output:
// Reset
24 changes: 24 additions & 0 deletions interp/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -1950,10 +1950,12 @@ func getMethodByName(n *node) {
}
val = v
}

if met := val.value.MethodByName(name); met.IsValid() {
getFrame(f, l).data[i] = met
return next
}

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
Expand All @@ -1963,10 +1965,32 @@ func getMethodByName(n *node) {
}
return next
}

m, li := typ.lookupMethod(name)

// Try harder to find a matching embedded valueInterface.
// TODO (marc): make sure it works for arbitrary depth and breadth.
if m == nil && isStruct(val.node.typ) {
v := val.value
for v.Type().Kind() == reflect.Ptr {
v = v.Elem()
}
nf := v.NumField()
for i := 0; i < nf; i++ {
var ok bool
if val, ok = v.Field(i).Interface().(valueInterface); !ok {
continue
}
if m, li = val.node.typ.lookupMethod(name); m != nil {
break
}
}
}

if m == nil {
panic(n.cfgErrorf("method not found: %s", name))
}

fr := f.clone(!fork)
nod := *m
nod.val = &nod
Expand Down

0 comments on commit ab869c8

Please sign in to comment.