fix: correct embedded method handling on hybrid struct (#162)
This commit is contained in:
committed by
Ludovic Fernandez
parent
800ad0e557
commit
37f93f0392
34
_test/method17.go
Normal file
34
_test/method17.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
type MyTime struct {
|
||||
time.Time
|
||||
index int
|
||||
}
|
||||
|
||||
func (m MyTime) Foo() {
|
||||
minute := m.Minute()
|
||||
fmt.Println("minute:", minute)
|
||||
}
|
||||
|
||||
func (m *MyTime) Bar() {
|
||||
second := m.Second()
|
||||
fmt.Println("second:", second)
|
||||
}
|
||||
|
||||
func main() {
|
||||
t := MyTime{}
|
||||
t.Time = time.Date(2009, time.November, 10, 23, 4, 5, 0, time.UTC)
|
||||
t.Foo()
|
||||
t.Bar()
|
||||
(&t).Bar()
|
||||
}
|
||||
|
||||
// Output:
|
||||
// minute: 4
|
||||
// second: 5
|
||||
// second: 5
|
||||
28
_test/method18.go
Normal file
28
_test/method18.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"compress/gzip"
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type GzipResponseWriter struct {
|
||||
http.ResponseWriter
|
||||
index int
|
||||
gw *gzip.Writer
|
||||
}
|
||||
|
||||
type GzipResponseWriterWithCloseNotify struct {
|
||||
*GzipResponseWriter
|
||||
}
|
||||
|
||||
func (w GzipResponseWriterWithCloseNotify) CloseNotify() <-chan bool {
|
||||
return w.ResponseWriter.(http.CloseNotifier).CloseNotify()
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println("hello")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
@@ -1027,6 +1027,10 @@ 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
|
||||
n.val = append([]int{m.Index}, lind...)
|
||||
n.typ = &Type{cat: ValueT, rtype: m.Type}
|
||||
} else if ti := n.typ.lookupField(n.child[1].ident); len(ti) > 0 {
|
||||
// Handle struct field
|
||||
n.val = ti
|
||||
|
||||
@@ -39,8 +39,8 @@ type Node struct {
|
||||
// Receiver stores method receiver object access path
|
||||
type Receiver struct {
|
||||
node *Node // receiver value for alias and struct types
|
||||
val reflect.Value // receiver value for interface type
|
||||
index []int // path in receiver value for interface type
|
||||
val reflect.Value // receiver value for interface type and value type
|
||||
index []int // path in receiver value for interface or value type
|
||||
}
|
||||
|
||||
// Frame contains values for the current execution level (a function context)
|
||||
|
||||
@@ -882,6 +882,27 @@ func getPtrIndexSeq(n *Node) {
|
||||
}
|
||||
}
|
||||
|
||||
func getIndexSeqMethod(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) Builtin {
|
||||
f.data[i] = value(f).Elem().FieldByIndex(fi).Method(mi)
|
||||
return next
|
||||
}
|
||||
} else {
|
||||
n.exec = func(f *Frame) Builtin {
|
||||
f.data[i] = value(f).FieldByIndex(fi).Method(mi)
|
||||
return next
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func negate(n *Node) {
|
||||
i := n.findex
|
||||
value := genValue(n.child[0])
|
||||
|
||||
@@ -503,7 +503,7 @@ func (t *Type) getMethod(name string) *Node {
|
||||
}
|
||||
|
||||
// lookupMethod returns a pointer to method definition associated to type t
|
||||
// and the list of indices to access the right struct field, in case of a promoted method
|
||||
// and the list of indices to access the right struct field, in case of an embedded method
|
||||
func (t *Type) lookupMethod(name string) (*Node, []int) {
|
||||
if t.cat == PtrT {
|
||||
return t.val.lookupMethod(name)
|
||||
@@ -523,6 +523,26 @@ func (t *Type) lookupMethod(name string) (*Node, []int) {
|
||||
return m, index
|
||||
}
|
||||
|
||||
// lookupBinMethod returns a method and a path to access a field in a struct object (the receiver)
|
||||
func (t *Type) lookupBinMethod(name string) (reflect.Method, []int, bool) {
|
||||
if t.cat == PtrT {
|
||||
return t.val.lookupBinMethod(name)
|
||||
}
|
||||
var index []int
|
||||
m, ok := t.TypeOf().MethodByName(name)
|
||||
if !ok {
|
||||
for i, f := range t.field {
|
||||
if f.embed {
|
||||
if m2, index2, ok2 := f.typ.lookupBinMethod(name); ok2 {
|
||||
index = append([]int{i}, index2...)
|
||||
return m2, index, ok2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return m, index, ok
|
||||
}
|
||||
|
||||
func exportName(s string) string {
|
||||
if canExport(s) {
|
||||
return s
|
||||
|
||||
Reference in New Issue
Block a user