Propagate method receiver info accross assignments

This commit is contained in:
Marc Vertes
2018-11-05 15:55:14 +01:00
parent 9b3c3f27b3
commit 314ceb15a7
5 changed files with 67 additions and 11 deletions

21
_test/method13.go Normal file
View File

@@ -0,0 +1,21 @@
package main
type Coord struct {
x, y int
}
func (c Coord) dist() int { return c.x*c.x + c.y*c.y }
type Point struct {
Coord
z int
}
func main() {
o := Point{Coord{3, 4}, 5}
f := o.dist
println(f())
}
// Output:
// 25

View File

@@ -38,6 +38,7 @@ type Symbol struct {
kind SymKind
typ *Type // Type of value
node *Node // Node value if index is negative
recv *Receiver // receiver node value, if sym refers to a method
index int // index of value in frame or -1
val interface{} // default value (used for constants)
path string // package path if typ.cat is SrcPkgT or BinPkgT
@@ -208,6 +209,7 @@ func (interp *Interpreter) Cfg(root *Node) []*Node {
scope.inc(interp)
n.child[0].val = n.child[1].val
n.child[0].typ = n.child[1].typ
n.child[0].recv = n.child[1].recv
n.child[0].findex = scope.size
if scope.global {
if sym, _, ok := scope.lookup(name); ok {
@@ -240,6 +242,7 @@ func (interp *Interpreter) Cfg(root *Node) []*Node {
n.typ = n.child[0].typ
if sym, level, ok := scope.lookup(n.child[0].ident); ok {
sym.typ = n.typ
sym.recv = n.child[1].recv
n.level = level
}
// If LHS is an indirection, get reference instead of value, to allow setting
@@ -338,7 +341,7 @@ func (interp *Interpreter) Cfg(root *Node) []*Node {
wireChild(n)
n.findex = scope.inc(interp)
n.typ = n.child[0].typ.val
n.recv = n
n.recv = &Receiver{node: n}
if n.child[0].typ.cat == MapT {
scope.size++ // Reserve an entry for getIndexMap 2nd return value
n.gen = getIndexMap
@@ -710,6 +713,7 @@ func (interp *Interpreter) Cfg(root *Node) []*Node {
n.val = nil
}
}
n.recv = n.sym.recv
} else {
if n.ident == "_" || n.anc.kind == Define || n.anc.kind == DefineX || n.anc.kind == RangeStmt || n.anc.kind == ValueSpec {
// Create a new local symbol for func argument or local var definition
@@ -807,7 +811,7 @@ func (interp *Interpreter) Cfg(root *Node) []*Node {
if n.typ == nil {
log.Fatal("typ should not be nil:", n.index, n.child[0])
}
log.Println(n.index, "selector", n.child[0].ident+"."+n.child[1].ident, n.typ.cat)
//log.Println(n.index, "selector", n.child[0].ident+"."+n.child[1].ident, n.typ.cat)
if n.typ.cat == ValueT {
// Handle object defined in runtime
if method, ok := n.typ.rtype.MethodByName(n.child[1].ident); ok {
@@ -889,10 +893,9 @@ func (interp *Interpreter) Cfg(root *Node) []*Node {
n.gen = nop
n.kind = BasicLit
n.val = m
n.child[1].val = lind
//n.child[1].val = lind
n.typ = m.typ
n.recv = n.child[0]
log.Println(n.index, "method recv", m.index, n.recv.index, lind)
n.recv = &Receiver{node: n.child[0], index: lind}
} else {
// Handle promoted field in embedded struct
if ti := n.typ.lookupField(n.child[1].ident); len(ti) > 0 {
@@ -1096,8 +1099,8 @@ func valueGenerator(n *Node, i int) func(*Frame) reflect.Value {
}
func genValueRecv(n *Node) func(*Frame) reflect.Value {
v := genValue(n.recv)
fi := n.child[1].val.([]int)
v := genValue(n.recv.node)
fi := n.recv.index
if len(fi) == 0 {
return v

View File

@@ -22,7 +22,7 @@ type Node struct {
kind Kind // kind of node
sym *Symbol // associated symbol
typ *Type // type of value in frame, or nil
recv *Node // method receiver node for call, or nil
recv *Receiver // method receiver node for call, or nil
frame *Frame // frame pointer, only used for script callbacks from runtime (wrapNode)
types []reflect.Type // frame types, used by function litterals only
framepos []int // frame positions of function parameters
@@ -35,6 +35,12 @@ type Node struct {
ident string // set if node is a var or func
}
// Receiver stores method receiver object access path
type Receiver struct {
node *Node
index []int
}
// Frame contains values for the current execution level
type Frame struct {
anc *Frame // ancestor frame (global space)

View File

@@ -603,7 +603,6 @@ func main() {
pos, neg := adder(), adder()
for i := 0; i < 10; i++ {
println(pos(i), neg(0-2*i))
}
}`
i := NewInterpreter(Opt{Entry: "main"}, "closure2.go")
@@ -1799,6 +1798,34 @@ func main() {
// 25
}
func Example_method13() {
src := `
package main
type Coord struct {
x, y int
}
func (c Coord) dist() int { return c.x*c.x + c.y*c.y }
type Point struct {
Coord
z int
}
func main() {
o := Point{Coord{3, 4}, 5}
f := o.dist
println(f())
}
`
i := NewInterpreter(Opt{Entry: "main"}, "method13.go")
i.Eval(src)
// Output:
// 25
}
func Example_method2() {
src := `
package main

View File

@@ -531,7 +531,6 @@ func call(n *Node) {
n.exec = func(f *Frame) Builtin {
def := value(f).Interface().(*Node)
log.Println(n.index, "def:", def)
anc := f
// Get closure frame context (if any)
if def.frame != nil {
@@ -547,7 +546,7 @@ func call(n *Node) {
}
// copy input parameters from caller
for i, v := range values {
log.Println(n.index, i, def.framepos[i], nf.data[def.framepos[i]].Kind(), v(f).Kind())
//log.Println(n.index, i, def.framepos[i], nf.data[def.framepos[i]].Kind(), v(f).Kind())
nf.data[def.framepos[i]].Set(v(f))
}