diff --git a/_test/struct20.go b/_test/struct20.go new file mode 100644 index 00000000..b1fdc030 --- /dev/null +++ b/_test/struct20.go @@ -0,0 +1,21 @@ +package main + +type SecretProvider func(user, realm string) string + +type BasicAuth struct { + Realm string + Secrets SecretProvider +} + +func (a *BasicAuth) CheckAuth() string { return a.Secrets("me", a.Realm) } + +func secretBasic(user, realm string) string { return user + "-" + realm } + +func main() { + b := &BasicAuth{"test", secretBasic} + s := b.CheckAuth() + println(s) +} + +// Output: +// me-test diff --git a/_test/struct21.go b/_test/struct21.go new file mode 100644 index 00000000..02da1799 --- /dev/null +++ b/_test/struct21.go @@ -0,0 +1,22 @@ +package main + +type SecretProvider func(user, realm string) string + +type BasicAuth struct { + Realm string + Secrets SecretProvider +} + +func (a *BasicAuth) CheckAuth() string { return a.Secrets("me", a.Realm) } + +func (a *BasicAuth) secretBasic(user, realm string) string { return a.Realm + "-" + user + "-" + realm } + +func main() { + b := &BasicAuth{Realm: "test"} + b.Secrets = b.secretBasic + s := b.CheckAuth() + println(s) +} + +// Output: +// test-me-test diff --git a/interp/cfg.go b/interp/cfg.go index 7b0cc2f6..07e5af35 100644 --- a/interp/cfg.go +++ b/interp/cfg.go @@ -1151,6 +1151,11 @@ func (interp *Interpreter) Cfg(root *Node) ([]*Node, error) { case PtrT: n.typ = n.typ.fieldSeq(ti) n.gen = getPtrIndexSeq + 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} + } default: n.gen = getIndexSeq n.typ = n.typ.fieldSeq(ti) diff --git a/interp/run.go b/interp/run.go index 9771a688..a32decfb 100644 --- a/interp/run.go +++ b/interp/run.go @@ -8,6 +8,8 @@ import ( "reflect" ) +func init() { log.SetFlags(log.Lshortfile) } + // Builtin type defines functions which run at CFG execution type Builtin func(f *Frame) Builtin @@ -400,7 +402,11 @@ func _panic(n *Node) { } func genFunctionWrapper(n *Node) func(*Frame) reflect.Value { - def := n.val.(*Node) + var def *Node + var ok bool + if def, ok = n.val.(*Node); !ok { + return genValueAsFunctionWrapper(n) + } setExec(def.child[3].start) start := def.child[3].start numRet := len(def.typ.ret) @@ -1446,12 +1452,13 @@ func compositeSparse(n *Node) { values := make(map[int]func(*Frame) reflect.Value) a, _ := n.typ.zero() for _, c := range child { + c1 := c.child[1] field := n.typ.fieldIndex(c.child[0].ident) - convertLiteralValue(c.child[1], n.typ.field[field].typ.TypeOf()) - if c.typ.cat == FuncT { - values[field] = genFunctionWrapper(c.child[1]) + convertLiteralValue(c1, n.typ.field[field].typ.TypeOf()) + if c1.typ.cat == FuncT { + values[field] = genFunctionWrapper(c1) } else { - values[field] = genValue(c.child[1]) + values[field] = genValue(c1) } } diff --git a/interp/value.go b/interp/value.go index 9c03f7e6..39b9614d 100644 --- a/interp/value.go +++ b/interp/value.go @@ -44,6 +44,13 @@ func genValueRecv(n *Node) func(*Frame) reflect.Value { } } +func genValueAsFunctionWrapper(n *Node) func(*Frame) reflect.Value { + v := genValue(n) + return func(f *Frame) reflect.Value { + return genFunctionWrapper(v(f).Interface().(*Node))(f) + } +} + func genValueAs(n *Node, t reflect.Type) func(*Frame) reflect.Value { v := genValue(n) return func(f *Frame) reflect.Value {