fix: handle binary methods where receiver is implicit
This commit is contained in:
16
_test/method29.go
Normal file
16
_test/method29.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
)
|
||||
|
||||
var lookupHost = net.DefaultResolver.LookupHost
|
||||
|
||||
func main() {
|
||||
res, err := lookupHost(context.Background(), "localhost")
|
||||
println(len(res) > 0, err == nil)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// true true
|
||||
20
_test/method30.go
Normal file
20
_test/method30.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package main
|
||||
|
||||
type T struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
func (t *T) foo(a string) string {
|
||||
return t.Name + a
|
||||
}
|
||||
|
||||
var g = &T{"global"}
|
||||
|
||||
var f = g.foo
|
||||
|
||||
func main() {
|
||||
println(f("-x"))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// global-x
|
||||
@@ -410,7 +410,11 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
|
||||
if src.typ, err = nodeType(interp, sc, src); err != nil {
|
||||
return
|
||||
}
|
||||
dest.typ = src.typ
|
||||
if src.typ.isBinMethod {
|
||||
dest.typ = &itype{cat: valueT, rtype: src.typ.methodCallType()}
|
||||
} else {
|
||||
dest.typ = src.typ
|
||||
}
|
||||
}
|
||||
if dest.typ.sizedef {
|
||||
dest.typ.size = arrayTypeLen(src)
|
||||
@@ -1097,7 +1101,7 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
|
||||
n.val = method.Index
|
||||
n.gen = getIndexBinMethod
|
||||
n.recv = &receiver{node: n.child[0]}
|
||||
n.typ = &itype{cat: valueT, rtype: method.Type}
|
||||
n.typ = &itype{cat: valueT, rtype: method.Type, isBinMethod: true}
|
||||
case n.typ.rtype.Kind() == reflect.Ptr:
|
||||
if field, ok := n.typ.rtype.Elem().FieldByName(n.child[1].ident); ok {
|
||||
n.typ = &itype{cat: valueT, rtype: field.Type}
|
||||
|
||||
@@ -60,6 +60,9 @@ func (interp *Interpreter) gta(root *node, rpath string) ([]*node, error) {
|
||||
err = n.cfgErrorf("use of untyped nil")
|
||||
return false
|
||||
}
|
||||
if typ.isBinMethod {
|
||||
typ = &itype{cat: valueT, rtype: typ.methodCallType(), isBinMethod: true}
|
||||
}
|
||||
sc.sym[dest.ident] = &symbol{kind: varSym, global: true, index: sc.add(typ), typ: typ, rval: val}
|
||||
if n.anc.kind == constDecl {
|
||||
sc.sym[dest.ident].kind = constSym
|
||||
|
||||
@@ -828,7 +828,9 @@ func callBin(n *node) {
|
||||
// method signature obtained from reflect.Type include 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 {
|
||||
rcvrOffset = 1
|
||||
if funcType.NumIn() > len(child) {
|
||||
rcvrOffset = 1
|
||||
}
|
||||
}
|
||||
|
||||
for i, c := range child {
|
||||
@@ -867,7 +869,6 @@ func callBin(n *node) {
|
||||
case interfaceT:
|
||||
values = append(values, genValueInterfaceValue(c))
|
||||
default:
|
||||
//values = append(values, genValue(c))
|
||||
values = append(values, genInterfaceWrapper(c, defType))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,22 +103,23 @@ type structField struct {
|
||||
|
||||
// itype defines the internal representation of types in the interpreter
|
||||
type itype struct {
|
||||
cat tcat // Type category
|
||||
field []structField // Array of struct fields if structT or interfaceT
|
||||
key *itype // Type of key element if MapT or nil
|
||||
val *itype // Type of value element if chanT, mapT, ptrT, aliasT, arrayT or variadicT
|
||||
arg []*itype // Argument types if funcT or nil
|
||||
ret []*itype // Return types if funcT or nil
|
||||
method []*node // Associated methods or nil
|
||||
name string // name of type within its package for a defined type
|
||||
path string // for a defined type, the package import path
|
||||
size int // Size of array if ArrayT
|
||||
rtype reflect.Type // Reflection type if ValueT, or nil
|
||||
incomplete bool // true if type must be parsed again (out of order declarations)
|
||||
untyped bool // true for a literal value (string or number)
|
||||
sizedef bool // true if array size is computed from type definition
|
||||
node *node // root AST node of type definition
|
||||
scope *scope // type declaration scope (in case of re-parse incomplete type)
|
||||
cat tcat // Type category
|
||||
field []structField // Array of struct fields if structT or interfaceT
|
||||
key *itype // Type of key element if MapT or nil
|
||||
val *itype // Type of value element if chanT, mapT, ptrT, aliasT, arrayT or variadicT
|
||||
arg []*itype // Argument types if funcT or nil
|
||||
ret []*itype // Return types if funcT or nil
|
||||
method []*node // Associated methods or nil
|
||||
name string // name of type within its package for a defined type
|
||||
path string // for a defined type, the package import path
|
||||
size int // Size of array if ArrayT
|
||||
rtype reflect.Type // Reflection type if ValueT, or nil
|
||||
incomplete bool // true if type must be parsed again (out of order declarations)
|
||||
untyped bool // true for a literal value (string or number)
|
||||
sizedef bool // true if array size is computed from type definition
|
||||
isBinMethod bool // true if the type refers to a bin method function
|
||||
node *node // root AST node of type definition
|
||||
scope *scope // type declaration scope (in case of re-parse incomplete type)
|
||||
}
|
||||
|
||||
// nodeType returns a type definition for the corresponding AST subtree
|
||||
@@ -482,7 +483,7 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
|
||||
if m, _ := lt.lookupMethod(name); m != nil {
|
||||
t, err = nodeType(interp, sc, m.child[2])
|
||||
} else if bm, _, _, ok := lt.lookupBinMethod(name); ok {
|
||||
t = &itype{cat: valueT, rtype: bm.Type}
|
||||
t = &itype{cat: valueT, rtype: bm.Type, isBinMethod: true}
|
||||
} else if ti := lt.lookupField(name); len(ti) > 0 {
|
||||
t = lt.fieldSeq(ti)
|
||||
} else if bs, _, ok := lt.lookupBinField(name); ok {
|
||||
@@ -809,6 +810,22 @@ func (t *itype) lookupBinField(name string) (s reflect.StructField, index []int,
|
||||
return s, index, ok
|
||||
}
|
||||
|
||||
// methodCallType returns a method function type without the receiver defined.
|
||||
// The input type must be a method function type with the receiver as the first input argument.
|
||||
func (t *itype) methodCallType() reflect.Type {
|
||||
it := []reflect.Type{}
|
||||
ni := t.rtype.NumIn()
|
||||
for i := 1; i < ni; i++ {
|
||||
it = append(it, t.rtype.In(i))
|
||||
}
|
||||
ot := []reflect.Type{}
|
||||
no := t.rtype.NumOut()
|
||||
for i := 0; i < no; i++ {
|
||||
ot = append(ot, t.rtype.Out(i))
|
||||
}
|
||||
return reflect.FuncOf(it, ot, t.rtype.IsVariadic())
|
||||
}
|
||||
|
||||
// getMethod returns a pointer to the method definition
|
||||
func (t *itype) getMethod(name string) *node {
|
||||
for _, m := range t.method {
|
||||
|
||||
Reference in New Issue
Block a user