yaegi icon indicating copy to clipboard operation
yaegi copied to clipboard

Can not import `github.com/apache/thrift/lib/go/thrift`

Open vitrun opened this issue 5 years ago • 7 comments

The following program thrift_script.go triggers a panic:

package main

import (
	"context"
	"github.com/apache/thrift/lib/go/thrift"
)

func Invoke(ctx context.Context, iproto thrift.TProtocol, oproto thrift.TProtocol) error {
	return nil
}


func main() {
}

Expected result:

$ go run ./thrift_script.go
// output
// no output

Got:

$ yaegi -syscall -unsafe thrift_script.go
// output
run: reflect: embedded type with methods not implemented if there is more than one field
goroutine 1 [running]:
runtime/debug.Stack(0x1, 0xc00050fe00, 0x40)
        /usr/local/go/src/runtime/debug/stack.go:24 +0x9d
github.com/traefik/yaegi/interp.(*Interpreter).eval.func1(0xc001379c70)
        /Users/bytedance/go/pkg/mod/github.com/traefik/[email protected]/interp/interp.go:480 +0xbc
panic(0x1951a20, 0x1c78fc0)
        /usr/local/go/src/runtime/panic.go:969 +0x166
reflect.StructOf(0xc000205520, 0x2, 0x2, 0x0, 0x0)
        /usr/local/go/src/reflect/type.go:2480 +0x312d
github.com/traefik/yaegi/interp.(*itype).refType(0xc000d6e1c0, 0xc0013781e8, 0x1a86700, 0x1, 0x22c2900)
        /Users/bytedance/go/pkg/mod/github.com/traefik/[email protected]/interp/type.go:1445 +0x95c
github.com/traefik/yaegi/interp.(*itype).refType(0xc000d6f260, 0xc0013781e8, 0xc001378a00, 0xc0013782c8, 0x13401f1)
        /Users/bytedance/go/pkg/mod/github.com/traefik/[email protected]/interp/type.go:1423 +0xcc0
github.com/traefik/yaegi/interp.(*itype).TypeOf(0xc000d6f260, 0xc000d6f260, 0x0)
        /Users/bytedance/go/pkg/mod/github.com/traefik/[email protected]/interp/type.go:1457 +0x96
github.com/traefik/yaegi/interp.(*itype).frameType(0xc000d6f260, 0xc0013783d8, 0xe0f18bf4)
        /Users/bytedance/go/pkg/mod/github.com/traefik/[email protected]/interp/type.go:1479 +0xed
github.com/traefik/yaegi/interp.(*scope).add(0xc000188000, 0xc000d6f260, 0xc0000392e0)
        /Users/bytedance/go/pkg/mod/github.com/traefik/[email protected]/interp/scope.go:188 +0x49
github.com/traefik/yaegi/interp.(*Interpreter).gta.func1(0xc0004fcd00, 0xc0002ca000)
        /Users/bytedance/go/pkg/mod/github.com/traefik/[email protected]/interp/gta.go:83 +0x497
github.com/traefik/yaegi/interp.(*node).Walk(0xc0004fcd00, 0xc001378bf8, 0x0)
...

Seems that it triggers an unsupported path of reflect.go

vitrun avatar Nov 03 '20 09:11 vitrun

According to discussion in https://github.com/golang/go/issues/15924 reflect.StructOf might be taught to create wrapper methods for "special cases that allow reusing the existing methods of embedded fields" which is exactly the special case that yaegi generally runs into.

bailsman avatar Apr 23 '21 23:04 bailsman

Recently I learned about the github.com/cosmos72/gomacro/xreflect package that works around many limitations in reflect.

Unsuccessfully, I tried using it to work around the "reflect: embedded type with methods not implemented if there is more than one field" error as follows. It has helped me import other packages that otherwise ran into similar errors, but no luck with thrift.

diff --git a/interp/type.go b/interp/type.go
index a2c9b6c..39dd51d 100644
--- a/interp/type.go
+++ b/interp/type.go
@@ -7,6 +7,7 @@ import (
        "reflect"
        "strconv"
        "sync"
+       "github.com/cosmos72/gomacro/xreflect"
 )

 // tcat defines interpreter type categories.
@@ -1494,7 +1495,7 @@ func (t *itype) refType(defined map[string]*itype, wrapRecursive bool) reflect.T
                if recursive && wrapRecursive {
                        t.rtype = interf
                } else {
-                       t.rtype = reflect.StructOf(fields)
+                       t.rtype = xStructOf(fields)
                }
        default:
                if z, _ := t.zero(); z.IsValid() {
@@ -1504,6 +1505,28 @@ func (t *itype) refType(defined map[string]*itype, wrapRecursive bool) reflect.T
        return t.rtype
 }

+func xStructOf(fields []reflect.StructField) (t reflect.Type) {
+       // Handle reflect.StructOf panic by trying with xreflect
+       defer func() {
+               if r := recover(); r != nil {
+                       universe := xreflect.NewUniverse()
+                       var xfields []xreflect.StructField
+                       for _, field := range fields {
+                               xfield := xreflect.StructField{
+                                       Name:  field.Name,
+                                       Type: universe.FromReflectType(field.Type),
+                                       Tag: field.Tag,
+                                       Anonymous: field.Anonymous,
+                               }
+                               xfields = append(xfields, xfield)
+                       }
+                       t = universe.StructOf(xfields).ReflectType()
+               }
+       }()
+       t = reflect.StructOf(fields)
+       return
+}
+
 // TypeOf returns the reflection type of dynamic interpreter type t.
 func (t *itype) TypeOf() reflect.Type {
        return t.refType(map[string]*itype{}, false)

Unfortunately, running the sample program with this patch then runs into another error:

$ yaegi -syscall ./thrift_script.go
run: ./thrift_script.go:5:2: import "github.com/apache/thrift/lib/go/thrift" error: /go/src/workspace/src/vendor/github.com/apache/thrift/lib/go/thrift/binary_protocol.go:218:25: too many arguments

Note: I have absolutely no idea if this is the correct way to use xreflect.

bailsman avatar Apr 27 '21 17:04 bailsman

I got an error at https://github.com/traefik/traefik/issues/9114

CFG post-order panic: reflect: embedded type with methods not implemented if there is more than one field

which might also related with this one.

hongbo-miao avatar Jun 21 '22 00:06 hongbo-miao

looks like this is the same issue... if I vendor aws-go-v2 SDK I get this

$ yaegi test -v .                                                                                                                                                                                                                      1202ms  Thu 20:51
panic: reflect: embedded type with methods not implemented if there is more than one field [recovered]
        panic: /Users/ygarciadiaz/projects/aws-sink/go/src/aws-sink/vendor/github.com/aws/smithy-go/transport/http/checksum_middleware.go:34:2: CFG post-order panic: reflect: embedded type with methods not implemented if there is more than one field

$ yaegi version
0.15.1

yoeluk avatar Jun 16 '23 04:06 yoeluk

+1 on the error with aws

Any known workarounds? This is a pretty big blocker for us.

lvijnck avatar Aug 08 '23 12:08 lvijnck

Getting the same issue using aws-go-v2 SDK

panic: reflect: embedded type with methods not implemented if there is more than one field [recovered]
        panic: plugins-local/src/github.com/x/y/vendor/github.com/aws/smithy-go/transport/http/checksum_middleware.go:34:2: CFG post-order panic: reflect: embedded type with methods not implemented if there is more than one field

goroutine 1 [running]:
github.com/traefik/yaegi/interp.(*Interpreter).cfg.func2.1()
        github.com/traefik/[email protected]/interp/cfg.go:601 +0x78
panic({0x103b952c0, 0x1055b4f40})
        runtime/panic.go:890 +0x263
reflect.StructOf({0xc0010f9a00, 0x4, 0xc001b8c640?})
        reflect/type.go:2551 +0x2709
github.com/traefik/yaegi/interp.(*itype).refType(0xc001afab40?, 0x0?)
        github.com/traefik/[email protected]/interp/type.go:2151 +0xd2a
github.com/traefik/yaegi/interp.(*itype).TypeOf(...)
        github.com/traefik/[email protected]/interp/type.go:2196
github.com/traefik/yaegi/interp.(*itype).frameType(0x10?)
        github.com/traefik/[email protected]/interp/type.go:2223 +0x18a
github.com/traefik/yaegi/interp.(*itype).frameType(0x100017dd7?)
        github.com/traefik/[email protected]/interp/type.go:2221 +0x136
github.com/traefik/yaegi/interp.(*scope).add(0xc001ba2360, 0xc0018b91d8?)
        github.com/traefik/[email protected]/interp/scope.go:210 +0x7b
github.com/traefik/yaegi/interp.compDefineX(0xc001ba2360, 0xc001360f00)
        github.com/traefik/[email protected]/interp/cfg.go:2328 +0x6a8
github.com/traefik/yaegi/interp.(*Interpreter).cfg.func2(0xc001360f00)
        github.com/traefik/[email protected]/interp/cfg.go:840 +0x1993
github.com/traefik/yaegi/interp.(*node).Walk(0xc001360f00, 0xc0018b9cf0, 0xc0018b9d38)
        github.com/traefik/[email protected]/interp/interp.go:294 +0xad
github.com/traefik/yaegi/interp.(*node).Walk(0xc001360dc0, 0xc0018b9cf0, 0xc0018b9d38)
        github.com/traefik/[email protected]/interp/interp.go:291 +0x75
github.com/traefik/yaegi/interp.(*node).Walk(0xc00135db80, 0xc0018b9cf0, 0xc0018b9d38)
        github.com/traefik/[email protected]/interp/interp.go:291 +0x75
github.com/traefik/yaegi/interp.(*node).Walk(0xc001302b40, 0xc0018b9cf0, 0xc0018b9d38)
        github.com/traefik/[email protected]/interp/interp.go:291 +0x75
github.com/traefik/yaegi/interp.(*Interpreter).cfg(0xc0014acd80, 0xc001302b40, 0xc001ba2360, {0xc0010eb681, 0x27}, {0xc00134c600, 0x4})
        github.com/traefik/[email protected]/interp/cfg.go:62 +0x2b4
github.com/traefik/yaegi/interp.(*Interpreter).importSrc(0xc0014acd80, {0xc000fc0af0, 0x65}, {0xc0010eb681, 0x27}, 0x1)
        github.com/traefik/[email protected]/interp/src.go:125 +0xda9
github.com/traefik/yaegi/interp.(*Interpreter).gta.func1(0xc001651040)
        github.com/traefik/[email protected]/interp/gta.go:273 +0x208d
github.com/traefik/yaegi/interp.(*node).Walk(0xc001651040, 0xc0018baad8, 0x0)
        github.com/traefik/[email protected]/interp/interp.go:287 +0x34
github.com/traefik/yaegi/interp.(*node).Walk(0xc001650780, 0xc0018baad8, 0x0)
        github.com/traefik/[email protected]/interp/interp.go:291 +0x75
github.com/traefik/yaegi/interp.(*node).Walk(0xc001650500, 0xc0018baad8, 0x0)
        github.com/traefik/[email protected]/interp/interp.go:291 +0x75
github.com/traefik/yaegi/interp.(*Interpreter).gta(0xc0014acd80, 0xc001650500, {0xc000fc0af0, 0x65}, {0xc0010eb291, 0x24}, {0xc0015b12a0, 0x6})
        github.com/traefik/[email protected]/interp/gta.go:20 +0x22b
github.com/traefik/yaegi/interp.(*Interpreter).importSrc(0xc0014acd80, {0xc000fc0690, 0x61}, {0xc0010eb291, 0x24}, 0x1)
        github.com/traefik/[email protected]/interp/src.go:108 +0x9a5
github.com/traefik/yaegi/interp.(*Interpreter).gta.func1(0xc001637040)
        github.com/traefik/[email protected]/interp/gta.go:273 +0x208d
github.com/traefik/yaegi/interp.(*node).Walk(0xc001637040, 0xc0018bb890, 0x0)
        github.com/traefik/[email protected]/interp/interp.go:287 +0x34
github.com/traefik/yaegi/interp.(*node).Walk(0xc001636c80, 0xc0018bb890, 0x0)
        github.com/traefik/[email protected]/interp/interp.go:291 +0x75
github.com/traefik/yaegi/interp.(*node).Walk(0xc001636a00, 0xc0018bb890, 0x0)
        github.com/traefik/[email protected]/interp/interp.go:291 +0x75
github.com/traefik/yaegi/interp.(*Interpreter).gta(0xc0014acd80, 0xc001636a00, {0xc000fc0690, 0x61}, {0xc0010eadb1, 0x20}, {0xc0015b0f30, 0x3})
        github.com/traefik/[email protected]/interp/gta.go:20 +0x22b
github.com/traefik/yaegi/interp.(*Interpreter).importSrc(0xc0014acd80, {0xc000fc03f0, 0x64}, {0xc0010eadb1, 0x20}, 0x1)
        github.com/traefik/[email protected]/interp/src.go:108 +0x9a5
github.com/traefik/yaegi/interp.(*Interpreter).gta.func1(0xc001609b80)
        github.com/traefik/[email protected]/interp/gta.go:273 +0x208d
github.com/traefik/yaegi/interp.(*node).Walk(0xc001609b80, 0xc0018bc648, 0x0)
        github.com/traefik/[email protected]/interp/interp.go:287 +0x34
github.com/traefik/yaegi/interp.(*node).Walk(0xc0016097c0, 0xc0018bc648, 0x0)
        github.com/traefik/[email protected]/interp/interp.go:291 +0x75
github.com/traefik/yaegi/interp.(*node).Walk(0xc001609540, 0xc0018bc648, 0x0)
        github.com/traefik/[email protected]/interp/interp.go:291 +0x75
github.com/traefik/yaegi/interp.(*Interpreter).gta(0xc0014acd80, 0xc001609540, {0xc000fc03f0, 0x64}, {0xc0010ead21, 0x23}, {0xc0015b08d0, 0x6})
        github.com/traefik/[email protected]/interp/gta.go:20 +0x22b
github.com/traefik/yaegi/interp.(*Interpreter).importSrc(0xc0014acd80, {0xc000084c80, 0x41}, {0xc0010ead21, 0x23}, 0x1)
        github.com/traefik/[email protected]/interp/src.go:108 +0x9a5
github.com/traefik/yaegi/interp.(*Interpreter).gta.func1(0xc0015f8b40)
        github.com/traefik/[email protected]/interp/gta.go:273 +0x208d
github.com/traefik/yaegi/interp.(*node).Walk(0xc0015f8b40, 0xc0018bd400, 0x0)
        github.com/traefik/[email protected]/interp/interp.go:287 +0x34
github.com/traefik/yaegi/interp.(*node).Walk(0xc0015f8500, 0xc0018bd400, 0x0)
        github.com/traefik/[email protected]/interp/interp.go:291 +0x75
github.com/traefik/yaegi/interp.(*node).Walk(0xc0015f8280, 0xc0018bd400, 0x0)
        github.com/traefik/[email protected]/interp/interp.go:291 +0x75
github.com/traefik/yaegi/interp.(*Interpreter).gta(0xc0014acd80, 0xc0015f8280, {0xc000084c80, 0x41}, {0xc000084aa1, 0x41}, {0xc0015b04e0, 0x3})
        github.com/traefik/[email protected]/interp/gta.go:20 +0x22b
github.com/traefik/yaegi/interp.(*Interpreter).importSrc(0xc0014acd80, {0xc000eec200, 0x39}, {0xc000084aa1, 0x41}, 0x1)
        github.com/traefik/[email protected]/interp/src.go:108 +0x9a5
github.com/traefik/yaegi/interp.(*Interpreter).gta.func1(0xc0015b6b40)
        github.com/traefik/[email protected]/interp/gta.go:273 +0x208d
github.com/traefik/yaegi/interp.(*node).Walk(0xc0015b6b40, 0xc0018be1b8, 0x0)
        github.com/traefik/[email protected]/interp/interp.go:287 +0x34
github.com/traefik/yaegi/interp.(*node).Walk(0xc000eb7900, 0xc0018be1b8, 0x0)
        github.com/traefik/[email protected]/interp/interp.go:291 +0x75
github.com/traefik/yaegi/interp.(*node).Walk(0xc000eb7680, 0xc0018be1b8, 0x0)
        github.com/traefik/[email protected]/interp/interp.go:291 +0x75
github.com/traefik/yaegi/interp.(*Interpreter).gta(0xc0014acd80, 0xc000eb7680, {0xc000eec200, 0x39}, {0xc000eb5f81, 0x39}, {0xc000ebc0c0, 0x1e})
        github.com/traefik/[email protected]/interp/gta.go:20 +0x22b
github.com/traefik/yaegi/interp.(*Interpreter).importSrc(0xc0014acd80, {0xc0014a78e0, 0x4}, {0xc000eb5f81, 0x39}, 0x1)
        github.com/traefik/[email protected]/interp/src.go:108 +0x9a5
github.com/traefik/yaegi/interp.(*Interpreter).gta.func1(0xc000eb7180)
        github.com/traefik/[email protected]/interp/gta.go:273 +0x208d
github.com/traefik/yaegi/interp.(*node).Walk(0xc000eb7180, 0xc0018bef70, 0x0)
        github.com/traefik/[email protected]/interp/interp.go:287 +0x34
github.com/traefik/yaegi/interp.(*node).Walk(0xc000eb6f00, 0xc0018bef70, 0x0)
        github.com/traefik/[email protected]/interp/interp.go:291 +0x75
github.com/traefik/yaegi/interp.(*node).Walk(0xc000eb6500, 0xc0018bef70, 0x0)
        github.com/traefik/[email protected]/interp/interp.go:291 +0x75
github.com/traefik/yaegi/interp.(*Interpreter).gta(0xc0014acd80, 0xc000eb6500, {0xc0014a78e0, 0x4}, {0xc0014a78e0, 0x4}, {0xc0014a78e0, 0x4})
        github.com/traefik/[email protected]/interp/gta.go:20 +0x22b
github.com/traefik/yaegi/interp.(*Interpreter).gtaRetry(0xc0014acd80?, {0xc00120d150?, 0xc0014aabd0?, 0xc00120d098?}, {0xc0014a78e0, 0x4}, {0xc0014a78e0, 0x4})
        github.com/traefik/[email protected]/interp/gta.go:395 +0x15d
github.com/traefik/yaegi/interp.(*Interpreter).CompileAST(0xc0014acd80, {0x1055ea140?, 0xc0014aabd0?})
        github.com/traefik/[email protected]/interp/program.go:92 +0x17f
github.com/traefik/yaegi/interp.(*Interpreter).compileSrc(0xc0014acd80, {0xc000084460?, 0x1?}, {0x0?, 0xc000084460?}, 0xf0?)
        github.com/traefik/[email protected]/interp/program.go:64 +0xb8
github.com/traefik/yaegi/interp.(*Interpreter).eval(0xc0014acd80, {0xc000084460?, 0xc00120d3c0?}, {0x0?, 0x1?}, 0x0?)
        github.com/traefik/[email protected]/interp/interp.go:556 +0x28
github.com/traefik/yaegi/interp.(*Interpreter).Eval(...)
        github.com/traefik/[email protected]/interp/interp.go:498
github.com/traefik/traefik/v2/pkg/plugins.NewBuilder(0x0, 0x0?, 0xc000912210?)
        github.com/traefik/traefik/v2/pkg/plugins/builder.go:104 +0xdc6
main.createPluginBuilder(0xc00084e080?)
        github.com/traefik/traefik/v2/cmd/traefik/plugins.go:18 +0x35
main.setupServer(0xc00084e080)
        github.com/traefik/traefik/v2/cmd/traefik/traefik.go:214 +0x537
main.runCmd(0xc00084e080)
        github.com/traefik/traefik/v2/cmd/traefik/traefik.go:117 +0x3e5
main.main.func1({0xc0003695e0?, 0xc000074050?, 0x0?})
        github.com/traefik/traefik/v2/cmd/traefik/traefik.go:62 +0x1f
github.com/traefik/paerser/cli.run(0xc00084e100, {0xc000074050?, 0x1, 0x1})
        github.com/traefik/[email protected]/cli/commands.go:133 +0x269
github.com/traefik/paerser/cli.execute(0xc00084e100, {0xc000074040?, 0x2, 0x2}, 0xa0?)
        github.com/traefik/[email protected]/cli/commands.go:67 +0x2cc
github.com/traefik/paerser/cli.Execute(...)
        github.com/traefik/[email protected]/cli/commands.go:51
main.main()
        github.com/traefik/traefik/v2/cmd/traefik/traefik.go:78 +0x405
❯ traefik version
Version:      2.10.4
Codename:     cheddar
Go version:   go1.20.6
Built:        I don't remember exactly
OS/Arch:      darwin/amd64

v1sion avatar Aug 31 '23 12:08 v1sion