fix: correct handling of func in struct fields (#99)
Wrap functions in struct fields in `reflect.Value` to have a consistent representation of function inside and outside the interpreter. Teach assign to wrap a function node if destination is reflect.Value The same needs to be done for composite literal, in a next commit.
This commit is contained in:
committed by
Ludovic Fernandez
parent
80527bb903
commit
abe384a765
@@ -951,8 +951,14 @@ func (interp *Interpreter) Cfg(root *Node) ([]*Node, error) {
|
||||
n.typ = n.typ.fieldSeq(ti)
|
||||
n.gen = getPtrIndexSeq
|
||||
default:
|
||||
n.typ = n.typ.fieldSeq(ti)
|
||||
n.gen = getIndexSeq
|
||||
n.typ = n.typ.fieldSeq(ti)
|
||||
if n.typ.cat == FuncT {
|
||||
// function in a struct field is always wrapped in reflect.Value
|
||||
rtype := n.typ.TypeOf()
|
||||
n.typ = &Type{cat: ValueT, rtype: rtype}
|
||||
n.fsize = rtype.NumOut()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err = n.cfgError("undefined selector: %s", n.child[1].ident)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package interp_test
|
||||
|
||||
import (
|
||||
"log"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
@@ -98,6 +99,55 @@ func TestEvalNil2(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestEvalStruct0(t *testing.T) {
|
||||
i := interp.New(interp.Opt{})
|
||||
evalCheck(t, i, `
|
||||
type Fromage struct {
|
||||
Name string
|
||||
Call func(string) string
|
||||
}
|
||||
|
||||
func f() string {
|
||||
a := Fromage{}
|
||||
a.Name = "test"
|
||||
a.Call = func(s string) string { return s }
|
||||
|
||||
return a.Call(a.Name)
|
||||
}
|
||||
`)
|
||||
|
||||
v := evalCheck(t, i, `f()`)
|
||||
if v.Interface().(string) != "test" {
|
||||
t.Fatalf("expected test, got %v", v)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEvalStruct1(t *testing.T) {
|
||||
t.Skip("not yet implemented")
|
||||
log.SetFlags(log.Lshortfile)
|
||||
i := interp.New(interp.Opt{})
|
||||
evalCheck(t, i, `
|
||||
type Fromage struct {
|
||||
Name string
|
||||
Call func(string) string
|
||||
}
|
||||
|
||||
func f() string {
|
||||
a := Fromage{
|
||||
"test",
|
||||
func(s string) string { return s },
|
||||
}
|
||||
|
||||
return a.Call(a.Name)
|
||||
}
|
||||
`)
|
||||
|
||||
v := evalCheck(t, i, `f()`)
|
||||
if v.Interface().(string) != "test" {
|
||||
t.Fatalf("expected test, got %v", v)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEvalComposite0(t *testing.T) {
|
||||
i := interp.New(interp.Opt{})
|
||||
evalCheck(t, i, `
|
||||
|
||||
@@ -192,7 +192,6 @@ func assignX(n *Node) {
|
||||
|
||||
// assign implements single value assignment
|
||||
func assign(n *Node) {
|
||||
value := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
|
||||
if n.child[0].typ.cat == InterfaceT {
|
||||
@@ -203,7 +202,14 @@ func assign(n *Node) {
|
||||
return next
|
||||
}
|
||||
} else {
|
||||
value1 := genValue(n.lastChild())
|
||||
value := genValue(n)
|
||||
dest, src := n.child[0], n.lastChild()
|
||||
var value1 func(*Frame) reflect.Value
|
||||
if dest.typ.cat == ValueT && src.typ.cat == FuncT {
|
||||
value1 = genNodeWrapper(src)
|
||||
} else {
|
||||
value1 = genValue(src)
|
||||
}
|
||||
n.exec = func(f *Frame) Builtin {
|
||||
value(f).Set(value1(f))
|
||||
return next
|
||||
|
||||
Reference in New Issue
Block a user