Skip to content

Commit ab869c8

Browse files
authored
interp: improve method resolution for embedded interfaces
The function `getMethodByName()` is now able to look for embedded `valueInterface` field for matching methods in interface struct fields. Fixes #1439 and #1427.
1 parent b2aa636 commit ab869c8

File tree

2 files changed

+49
-0
lines changed

2 files changed

+49
-0
lines changed

_test/issue-1439.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package main
2+
3+
type Transformer interface {
4+
Reset()
5+
}
6+
7+
type Encoder struct {
8+
Transformer
9+
}
10+
11+
type nop struct{}
12+
13+
func (nop) Reset() { println("Reset") }
14+
15+
func f(e Transformer) {
16+
e.Reset()
17+
}
18+
19+
func main() {
20+
e := Encoder{Transformer: nop{}}
21+
f(e)
22+
}
23+
24+
// Output:
25+
// Reset

interp/run.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1950,10 +1950,12 @@ func getMethodByName(n *node) {
19501950
}
19511951
val = v
19521952
}
1953+
19531954
if met := val.value.MethodByName(name); met.IsValid() {
19541955
getFrame(f, l).data[i] = met
19551956
return next
19561957
}
1958+
19571959
typ := val.node.typ
19581960
if typ.node == nil && typ.cat == valueT {
19591961
// happens with a var of empty interface type, that has value of concrete type
@@ -1963,10 +1965,32 @@ func getMethodByName(n *node) {
19631965
}
19641966
return next
19651967
}
1968+
19661969
m, li := typ.lookupMethod(name)
1970+
1971+
// Try harder to find a matching embedded valueInterface.
1972+
// TODO (marc): make sure it works for arbitrary depth and breadth.
1973+
if m == nil && isStruct(val.node.typ) {
1974+
v := val.value
1975+
for v.Type().Kind() == reflect.Ptr {
1976+
v = v.Elem()
1977+
}
1978+
nf := v.NumField()
1979+
for i := 0; i < nf; i++ {
1980+
var ok bool
1981+
if val, ok = v.Field(i).Interface().(valueInterface); !ok {
1982+
continue
1983+
}
1984+
if m, li = val.node.typ.lookupMethod(name); m != nil {
1985+
break
1986+
}
1987+
}
1988+
}
1989+
19671990
if m == nil {
19681991
panic(n.cfgErrorf("method not found: %s", name))
19691992
}
1993+
19701994
fr := f.clone(!fork)
19711995
nod := *m
19721996
nod.val = &nod

0 commit comments

Comments
 (0)