Skip to content

Commit

Permalink
fix: binary method lookup works for struct field pointer receiver
Browse files Browse the repository at this point in the history
  • Loading branch information
mvertes authored and traefiker committed Sep 19, 2019
1 parent c8ae73a commit 9abaeeb
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 8 deletions.
20 changes: 20 additions & 0 deletions _test/method27.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package main

import (
"fmt"
"net/http"
)

type AuthenticatedRequest struct {
http.Request
Username string
}

func main() {
a := &AuthenticatedRequest{}
fmt.Println("ua:", a.UserAgent())

}

// Output:
// ua:
8 changes: 6 additions & 2 deletions interp/cfg.go
Original file line number Diff line number Diff line change
Expand Up @@ -1104,8 +1104,12 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
n.typ = m.typ
n.recv = &receiver{node: n.child[0], index: lind}
}
} else if m, lind, ok := n.typ.lookupBinMethod(n.child[1].ident); ok {
n.gen = getIndexSeqMethod
} else if m, lind, isPtr, ok := n.typ.lookupBinMethod(n.child[1].ident); ok {
if isPtr {
n.gen = getIndexSeqPtrMethod
} else {
n.gen = getIndexSeqMethod
}
n.val = append([]int{m.Index}, lind...)
n.typ = &itype{cat: valueT, rtype: m.Type}
} else if ti := n.typ.lookupField(n.child[1].ident); len(ti) > 0 {
Expand Down
23 changes: 22 additions & 1 deletion interp/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,7 @@ func genInterfaceWrapper(n *node, typ reflect.Type) func(*frame) reflect.Value {
methods[i], indexes[i] = n.typ.lookupMethod(names[i])
if methods[i] == nil && n.typ.cat != nilT {
// interpreted method not found, look for binary method, possibly embedded
_, indexes[i], _ = n.typ.lookupBinMethod(names[i])
_, indexes[i], _, _ = n.typ.lookupBinMethod(names[i])
}
}
wrap := n.interp.getWrapper(typ)
Expand Down Expand Up @@ -1130,6 +1130,27 @@ func getIndexSeqField(n *node) {
}
}

func getIndexSeqPtrMethod(n *node) {
value := genValue(n.child[0])
index := n.val.([]int)
fi := index[1:]
mi := index[0]
i := n.findex
next := getExec(n.tnext)

if n.child[0].typ.TypeOf().Kind() == reflect.Ptr {
n.exec = func(f *frame) bltn {
f.data[i] = value(f).Elem().FieldByIndex(fi).Addr().Method(mi)
return next
}
} else {
n.exec = func(f *frame) bltn {
f.data[i] = value(f).FieldByIndex(fi).Addr().Method(mi)
return next
}
}
}

func getIndexSeqMethod(n *node) {
value := genValue(n.child[0])
index := n.val.([]int)
Expand Down
15 changes: 10 additions & 5 deletions interp/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -478,7 +478,7 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
default:
if m, _ := lt.lookupMethod(name); m != nil {
t, err = nodeType(interp, sc, m.child[2])
} else if bm, _, ok := lt.lookupBinMethod(name); ok {
} else if bm, _, _, ok := lt.lookupBinMethod(name); ok {
t = &itype{cat: valueT, rtype: bm.Type}
} else if ti := lt.lookupField(name); len(ti) > 0 {
t = lt.fieldSeq(ti)
Expand Down Expand Up @@ -758,23 +758,28 @@ func (t *itype) lookupMethod(name string) (*node, []int) {
}

// lookupBinMethod returns a method and a path to access a field in a struct object (the receiver)
func (t *itype) lookupBinMethod(name string) (reflect.Method, []int, bool) {
func (t *itype) lookupBinMethod(name string) (reflect.Method, []int, bool, bool) {
var isPtr bool
if t.cat == ptrT {
return t.val.lookupBinMethod(name)
}
var index []int
m, ok := t.TypeOf().MethodByName(name)
if !ok {
m, ok = reflect.PtrTo(t.TypeOf()).MethodByName(name)
isPtr = ok
}
if !ok {
for i, f := range t.field {
if f.embed {
if m2, index2, ok2 := f.typ.lookupBinMethod(name); ok2 {
if m2, index2, isPtr2, ok2 := f.typ.lookupBinMethod(name); ok2 {
index = append([]int{i}, index2...)
return m2, index, ok2
return m2, index, isPtr2, ok2
}
}
}
}
return m, index, ok
return m, index, isPtr, ok
}

func exportName(s string) string {
Expand Down

0 comments on commit 9abaeeb

Please sign in to comment.