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.