From 9b07e73b5e6b7b6adfa6629d1a4701850f5daba8 Mon Sep 17 00:00:00 2001 From: Marc Vertes Date: Thu, 12 Mar 2020 14:42:04 +0100 Subject: [PATCH] fix: resolve receiver for binary methods on non interface types --- _test/struct36.go | 21 +++++++++++++++++++++ interp/cfg.go | 1 + interp/run.go | 6 +++--- interp/type.go | 6 ++---- 4 files changed, 27 insertions(+), 7 deletions(-) create mode 100644 _test/struct36.go diff --git a/_test/struct36.go b/_test/struct36.go new file mode 100644 index 000000000..f1b1d10c1 --- /dev/null +++ b/_test/struct36.go @@ -0,0 +1,21 @@ +package main + +import ( + "net/http" + "strings" +) + +type S struct { + http.Client +} + +func main() { + var s S + if _, err := s.Get("url"); err != nil { + println(strings.Contains(err.Error(), "unsupported protocol scheme")) + } + return +} + +// Output: +// true diff --git a/interp/cfg.go b/interp/cfg.go index 944f4b821..d854e3d9d 100644 --- a/interp/cfg.go +++ b/interp/cfg.go @@ -1219,6 +1219,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) { } else { n.gen = getIndexSeqMethod } + n.recv = &receiver{node: n.child[0], index: lind} 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 { diff --git a/interp/run.go b/interp/run.go index 5db1887d0..43a2efe75 100644 --- a/interp/run.go +++ b/interp/run.go @@ -803,7 +803,7 @@ func pindex(i, variadic int) int { return variadic } -// Call a function from a bin import, accessible through reflect +// Callbin calls a function from a bin import, accessible through reflect. func callBin(n *node) { tnext := getExec(n.tnext) fnext := getExec(n.fnext) @@ -815,9 +815,9 @@ func callBin(n *node) { if funcType.IsVariadic() { variadic = funcType.NumIn() - 1 } - // method signature obtained from reflect.Type include receiver as 1st arg, except for interface types + // A method signature obtained from reflect.Type includes receiver as 1st arg, except for interface types. rcvrOffset := 0 - if recv := n.child[0].recv; recv != nil && recv.node.typ.TypeOf().Kind() != reflect.Interface { + if recv := n.child[0].recv; recv != nil && !isInterface(recv.node.typ) { if funcType.NumIn() > len(child) { rcvrOffset = 1 } diff --git a/interp/type.go b/interp/type.go index 1cc449fac..3538c786c 100644 --- a/interp/type.go +++ b/interp/type.go @@ -871,13 +871,11 @@ 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, bool) { - var isPtr bool +func (t *itype) lookupBinMethod(name string) (m reflect.Method, index []int, isPtr bool, ok bool) { if t.cat == ptrT { return t.val.lookupBinMethod(name) } - var index []int - m, ok := t.TypeOf().MethodByName(name) + m, ok = t.TypeOf().MethodByName(name) if !ok { m, ok = reflect.PtrTo(t.TypeOf()).MethodByName(name) isPtr = ok