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

Third-party imported type method is not callable from fast.Interp.Eval [gomacro repl works]

Skird opened this issue · comments

Hi, thanks for cool package!
I was playing around with it and got the following strange problem.

Small example here

package main

import (
	"fmt"
	"github.com/cosmos72/gomacro/fast"
	"github.com/holiman/uint256"
)

func main() {
	code := `
import (
	"github.com/holiman/uint256"
)
func Foo(x *uint256.Int) int {
	return x.Sign()
}
`
	interp := fast.New()
	interp.Eval(code)
	foo := interp.ValueOf("Foo").Interface().(func(*uint256.Int) int)

	y := uint256.NewInt(123)
	fmt.Println(foo(y))
}

It seems I'm successfully importing the library but when I'm trying to use any of uint256.Int methods I get an error.

// debug: running "go get github.com/holiman/uint256" ...
go: added github.com/holiman/uint256 v1.2.1
// debug: running "go mod tidy" ...
// debug: compiling plugin "/home/divashchenko/go/src/gomacro.imports/gomacro_pid_106507/import_1" ...
panic: repl.go:6:9: type *github.com/holiman/uint256.Int has no field or method "Sign": x.Sign [recovered]
        panic: repl.go:6:9: not a package: "x" in x.Sign <*ast.SelectorExpr>

goroutine 1 [running]:
github.com/cosmos72/gomacro/base/output.(*Stringer).Errorf(...)
        /home/divashchenko/go/pkg/mod/github.com/cosmos72/gomacro@v0.0.0-20230110102113-12bd30aad33f/base/output/output.go:96
github.com/cosmos72/gomacro/fast.(*Comp).compileType2(0xc0001cc540, {0x1a58910?, 0xc0004c04b0?}, 0x0)
        /home/divashchenko/go/pkg/mod/github.com/cosmos72/gomacro@v0.0.0-20230110102113-12bd30aad33f/fast/type.go:248 +0x1447
github.com/cosmos72/gomacro/fast.(*Comp).Type(...)
        /home/divashchenko/go/pkg/mod/github.com/cosmos72/gomacro@v0.0.0-20230110102113-12bd30aad33f/fast/type.go:148
github.com/cosmos72/gomacro/fast.(*Comp).Expr1OrType.func1()
        /home/divashchenko/go/pkg/mod/github.com/cosmos72/gomacro@v0.0.0-20230110102113-12bd30aad33f/fast/expr.go:206 +0x65
panic({0x177dea0, 0xc000276bd0})
        /usr/lib/go-1.19/src/runtime/panic.go:884 +0x212
github.com/cosmos72/gomacro/base/output.(*Stringer).Errorf(...)
        /home/divashchenko/go/pkg/mod/github.com/cosmos72/gomacro@v0.0.0-20230110102113-12bd30aad33f/base/output/output.go:96
github.com/cosmos72/gomacro/fast.(*Comp).SelectorExpr(0xc0001cc540, 0xc0004c04b0)
        /home/divashchenko/go/pkg/mod/github.com/cosmos72/gomacro@v0.0.0-20230110102113-12bd30aad33f/fast/selector.go:74 +0x914
github.com/cosmos72/gomacro/fast.(*Comp).expr(0xc0001cc540, {0x1a58910?, 0xc0004c04b0?}, 0x1645220?)
        /home/divashchenko/go/pkg/mod/github.com/cosmos72/gomacro@v0.0.0-20230110102113-12bd30aad33f/fast/expr.go:150 +0x145
github.com/cosmos72/gomacro/fast.(*Comp).expr1(0xc0001cc540, {0x1a58910?, 0xc0004c04b0?}, 0x82?)
        /home/divashchenko/go/pkg/mod/github.com/cosmos72/gomacro@v0.0.0-20230110102113-12bd30aad33f/fast/expr.go:101 +0x174
github.com/cosmos72/gomacro/fast.(*Comp).Expr1(...)
        /home/divashchenko/go/pkg/mod/github.com/cosmos72/gomacro@v0.0.0-20230110102113-12bd30aad33f/fast/expr.go:73
github.com/cosmos72/gomacro/fast.(*Comp).Expr1OrType(0x1645220?, {0x1a58910?, 0xc0004c04b0?})
        /home/divashchenko/go/pkg/mod/github.com/cosmos72/gomacro@v0.0.0-20230110102113-12bd30aad33f/fast/expr.go:209 +0x21f
github.com/cosmos72/gomacro/fast.(*Comp).CallExpr(0x100c000276b70?, 0xc0003b3a80)
        /home/divashchenko/go/pkg/mod/github.com/cosmos72/gomacro@v0.0.0-20230110102113-12bd30aad33f/fast/call.go:64 +0x47
github.com/cosmos72/gomacro/fast.(*Comp).expr(0xc0001cc540, {0x1a58370?, 0xc0003b3a80?}, 0x7fea512365b8?)
        /home/divashchenko/go/pkg/mod/github.com/cosmos72/gomacro@v0.0.0-20230110102113-12bd30aad33f/fast/expr.go:134 +0x345
github.com/cosmos72/gomacro/fast.(*Comp).expr1(0xc0001cc540, {0x1a58370?, 0xc0003b3a80?}, 0x1?)
        /home/divashchenko/go/pkg/mod/github.com/cosmos72/gomacro@v0.0.0-20230110102113-12bd30aad33f/fast/expr.go:101 +0x174
github.com/cosmos72/gomacro/fast.(*Comp).exprs(0x203000?, {0xc0003b7630, 0x1, 0x21e2920?})
        /home/divashchenko/go/pkg/mod/github.com/cosmos72/gomacro@v0.0.0-20230110102113-12bd30aad33f/fast/expr.go:63 +0x99
github.com/cosmos72/gomacro/fast.(*Comp).Return(0x1a588b0?, 0xc0004b8920)
        /home/divashchenko/go/pkg/mod/github.com/cosmos72/gomacro@v0.0.0-20230110102113-12bd30aad33f/fast/statement.go:614 +0xe6
github.com/cosmos72/gomacro/fast.(*Comp).Stmt(0xc0001cc540, {0x1a588b0?, 0xc0004b8920?})
        /home/divashchenko/go/pkg/mod/github.com/cosmos72/gomacro@v0.0.0-20230110102113-12bd30aad33f/fast/statement.go:102 +0x486
github.com/cosmos72/gomacro/fast.(*Comp).DeclFunc(0xc0001cc3c0, 0xc0004c4330)
        /home/divashchenko/go/pkg/mod/github.com/cosmos72/gomacro@v0.0.0-20230110102113-12bd30aad33f/fast/function.go:91 +0x768
github.com/cosmos72/gomacro/fast.(*Comp).Decl(0xc0001cc3c0?, {0x1a58580, 0xc0004c4330?})
        /home/divashchenko/go/pkg/mod/github.com/cosmos72/gomacro@v0.0.0-20230110102113-12bd30aad33f/fast/declaration.go:41 +0xb3
github.com/cosmos72/gomacro/fast.(*Comp).compileNode(0xc0001cc3c0, {0x1a56218?, 0xc0004c4330?}, 0x3)
        /home/divashchenko/go/pkg/mod/github.com/cosmos72/gomacro@v0.0.0-20230110102113-12bd30aad33f/fast/compile.go:449 +0x1fe
github.com/cosmos72/gomacro/fast.(*Comp).compileDecl(0xc0001cc3c0?, 0xc0003b3b00?)
        /home/divashchenko/go/pkg/mod/github.com/cosmos72/gomacro@v0.0.0-20230110102113-12bd30aad33f/fast/compile.go:415 +0x1f0
github.com/cosmos72/gomacro/fast.(*Comp).Compile(0xc0001cc3c0, {0x1a5d180, 0xc0004c0420})
        /home/divashchenko/go/pkg/mod/github.com/cosmos72/gomacro@v0.0.0-20230110102113-12bd30aad33f/fast/compile.go:375 +0x4b0
github.com/cosmos72/gomacro/fast.(*Interp).CompileAst(0xc0003b7520?, {0x1a5d180?, 0xc0004c0420?})
        /home/divashchenko/go/pkg/mod/github.com/cosmos72/gomacro@v0.0.0-20230110102113-12bd30aad33f/fast/repl.go:95 +0x12b
github.com/cosmos72/gomacro/fast.(*Interp).Compile(0x1802f29?, {0x1848ae6?, 0x1802f29?})
        /home/divashchenko/go/pkg/mod/github.com/cosmos72/gomacro@v0.0.0-20230110102113-12bd30aad33f/fast/repl.go:75 +0x35
github.com/cosmos72/gomacro/fast.(*Interp).Eval(0x8dc79c?, {0x1848ae6?, 0x8df1d9?})
        /home/divashchenko/go/pkg/mod/github.com/cosmos72/gomacro@v0.0.0-20230110102113-12bd30aad33f/fast/interpreter.go:261 +0x25
main.main()
        /home/divashchenko/workspace/tmp/goplay/main.go:19 +0x33

I also tried using interp.DeclType to introduce uint256.Int type from host to interpreter, with same result. However, if I create uint256.NewInt(123) in interpreter and use methods in host code it works.

I tried the same approach with another simple library github.com/bits-and-blooms/bitset and it worked.

That makes me think that problem is connected with type aliases (as it's declared as type Int [4]uint64).

Is this case not supported? Is there any workaround for that?

One more interesting example from attempted workaround

package main

import (
	"fmt"
	"github.com/cosmos72/gomacro/fast"
	"github.com/holiman/uint256"
)

func main() {
	code := `
import (
	"github.com/holiman/uint256"
)

sign := uint256.Int.Sign

func Foo(x *uint256.Int) int {
	return sign(x)
}
`
	interp := fast.New()
	interp.Eval(code)

	foo := interp.ValueOf("Foo").Interface().(func(int2 *uint256.Int) int)

	z := uint256.NewInt(123)
	fmt.Println(foo(z))
}

Fails with

// debug: running "go get github.com/holiman/uint256" ...
go: added github.com/holiman/uint256 v1.2.1
// debug: running "go mod tidy" ...
// debug: compiling plugin "/home/divashchenko/go/src/gomacro.imports/gomacro_pid_37124/import_1" ...
panic: reflect.Value.Addr of unaddressable value

goroutine 1 [running]:
reflect.Value.Addr({0x17fe4e0?, 0xc0002cb2c0?, 0x1?})
        /usr/lib/go-1.19/src/reflect/value.go:271 +0x65
github.com/cosmos72/gomacro/xreflect.Value.Addr(...)
        /home/divashchenko/go/pkg/mod/github.com/cosmos72/gomacro@v0.0.0-20230110102113-12bd30aad33f/xreflect/value.go:114
github.com/cosmos72/gomacro/fast.(*Comp).compileMethodAsFunc.func6({0xc0005965d0?, 0x1, 0x1})
        /home/divashchenko/go/pkg/mod/github.com/cosmos72/gomacro@v0.0.0-20230110102113-12bd30aad33f/fast/selector.go:909 +0xbc
github.com/cosmos72/gomacro/xreflect.MakeFunc.func1({0xc0005965b8, 0x1, 0x1?})
        /home/divashchenko/go/pkg/mod/github.com/cosmos72/gomacro@v0.0.0-20230110102113-12bd30aad33f/xreflect/wrap.go:39 +0xaa
reflect.Value.call({0x1658c20?, 0xc0002fbf70?, 0x7f3bfc913a68?}, {0x18027ed, 0x4}, {0xc0005965a0, 0x1, 0x1658c20?})
        /usr/lib/go-1.19/src/reflect/value.go:584 +0x8c5
reflect.Value.Call({0x1658c20?, 0xc0002fbf70?, 0xc0002b7830?}, {0xc0005965a0?, 0x100000000000475?, 0xc000197760?})
        /usr/lib/go-1.19/src/reflect/value.go:368 +0xbc
github.com/cosmos72/gomacro/xreflect.Value.Call({{0x1658c20?, 0xc0002fbf70?, 0x0?}}, {0xc000596588, 0x1, 0x92ddd2?})
        /home/divashchenko/go/pkg/mod/github.com/cosmos72/gomacro@v0.0.0-20230110102113-12bd30aad33f/xreflect/value.go:127 +0x113
github.com/cosmos72/gomacro/fast.callxr({{0x1658c20?, 0xc0002fbf70?, 0xc0002cb2c0?}}, {0xc000596588, 0x1, 0x1})
        /home/divashchenko/go/pkg/mod/github.com/cosmos72/gomacro@v0.0.0-20230110102113-12bd30aad33f/fast/call.go:453 +0x8e
github.com/cosmos72/gomacro/fast.(*Comp).callnret1.func2(0x17fe4e0?)
        /home/divashchenko/go/pkg/mod/github.com/cosmos72/gomacro@v0.0.0-20230110102113-12bd30aad33f/fast/callnret1.go:58 +0xee
github.com/cosmos72/gomacro/fast.(*Comp).varSetExpr.func3(0xc0001da320)
        /home/divashchenko/go/pkg/mod/github.com/cosmos72/gomacro@v0.0.0-20230110102113-12bd30aad33f/fast/var_set.go:2344 +0x2f
github.com/cosmos72/gomacro/fast.exec.func1(0xc0001da320?)
        /home/divashchenko/go/pkg/mod/github.com/cosmos72/gomacro@v0.0.0-20230110102113-12bd30aad33f/fast/code.go:171 +0x236
github.com/cosmos72/gomacro/fast.(*Comp).funcGeneric.func2.1({0xc000596540, 0x1, 0x0?})
        /home/divashchenko/go/pkg/mod/github.com/cosmos72/gomacro@v0.0.0-20230110102113-12bd30aad33f/fast/function.go:438 +0xf0
github.com/cosmos72/gomacro/xreflect.MakeFunc.func1({0xc000596528, 0x1, 0x1?})
        /home/divashchenko/go/pkg/mod/github.com/cosmos72/gomacro@v0.0.0-20230110102113-12bd30aad33f/xreflect/wrap.go:39 +0xaa
main.main()
        /home/divashchenko/workspace/tmp/goplay/main.go:33 +0x7e

It seems that in fast/selector.go:843 it falls into wrong branch (with comment // method declared by interpreted code, manually retrieve it.). In following snippet

var x uint256.Int
interp := fast.New()
typ := interp.TypeOf(x)
fmt.Println(typ.ReflectType().NumMethod())

something strange happens with typ.ReflectType(), it has NumMethods() == 0.
Tried to dig into it a bit more with no luck, but I hope it hepls :)

Sorry for the very late answer.

Yes, it's definitely strange because running the same code directly from gomacro repl works:

import "github.com/holiman/uint256"

func Foo(x *uint256.Int) int {
	return x.Sign()
}

y := uint256.NewInt(123)
Foo(y)

produces the following output:

// debug: running "go get github.com/holiman/uint256" ...
go: added github.com/holiman/uint256 v1.2.4
// debug: running "go mod tidy" ...
// debug: compiling plugin "/home/max/go/src/gomacro.imports/gomacro_pid_17289/import_1" ...
1       // int

I am debugging this issue, and it's specific to methods attached to non-struct types.

Package github.com/holiman/uint256 defines type Int as follows:

type Int [4]uint64

then defines methods with pointer receiver *Int, as for example

func (z *Int) Sign() int {
  // ...
}

Which is perfectly legal, but less tested in gomacro than methods attached to structs.

Continuing the analysis...

Fixed in commit 960f329

It was a bug in method lookup: it checked for types that cannot have methods and failed early in such case,
but the logic for the early failure was bugged and worked by chance only if experimental generics were enabled.