cosmos72 / gomacro

Interactive Go interpreter and debugger with REPL, Eval, generics and Lisp-like macros

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Proxy can mix the called method of the imported structure

rabits opened this issue · comments

commented

Found another interesting behavior: it looks like order of the func fields in proxy matters:

package main

import (
        "fmt"
        "reflect"

        "github.com/cosmos72/gomacro/fast"
        "github.com/cosmos72/gomacro/imports"
)

type V1Interface interface {
        GetName() string
        GetType() string
}

type P_V1Interface struct {
        Object   interface{}
        GetType_ func(interface{}) string
        GetName_ func(interface{}) string
}

func (P *P_V1Interface) GetName() string {
        return P.GetName_(P.Object)
}
func (P *P_V1Interface) GetType() string {
        return P.GetType_(P.Object)
}

var script = `package test

type V1Data struct {
    Name string
    Type string
}
func (t V1Data) GetName() string {
    return t.Name
}
func (t V1Data) GetType() string {
    return t.Type
}
`

func main() {
        interp := fast.New()

        imports.Packages["github.com/org/project/pkg/modules"] = imports.Package{
                Binds: map[string]reflect.Value{},
                Types: map[string]reflect.Type{
                        "V1Interface": reflect.TypeOf((*V1Interface)(nil)).Elem(),
                },
                Proxies: map[string]reflect.Type{
                        "V1Interface": reflect.TypeOf((*P_V1Interface)(nil)).Elem(),
                },
                Untypeds: map[string]string{},
                Wrappers: map[string][]string{},
        }
        interp.ImportPackage("", "github.com/org/project/pkg/modules")

        interp.Eval(script)

        intv, _ := interp.Eval1(`modules.V1Interface(V1Data{Name: "name_data", Type: "type_data"})`)
        intp := intv.Interface().(V1Interface)
        fmt.Printf("Name: %v\n", intp.GetName())
        fmt.Printf("Type: %v\n", intp.GetType())
}

This example will print:

Name: type_data
Type: name_data

And if we will switch the order in proxy:

...
type P_V1Interface struct {
        Object   interface{}
        GetName_ func(interface{}) string
        GetType_ func(interface{}) string
}
...

The result will be just fine:

Name: name_data
Type: type_data

Seems the other modifications are not affecting the values - in scripts it doesn't matter so if compiled proxy was done properly it will be safe for scripts. But also it could call the function with the wrong arguments - and here is just luck helped me to debug what was wrong.

Nice catch @rabits !

I guess this issue never emerged before because imports.Package structs usually appear only in autogenerated code (i.e. sources generated by the various gomacro imports mechanisms), rather than in user-written sources.

I will add a consistency check when gomacro loads the interface proxies contained in an imports.Package - it will check that fields of a proxy (beyond Object_, which must be the first field) are in the same order as interface methods retrieved with reflect.Type.Method(int) which currently means they must be in alphabetic (to be exact, lexicographic) order.

Fixed in commit 5a01d1f

commented

Great! Thank you very much)