yaegi icon indicating copy to clipboard operation
yaegi copied to clipboard

Exported interface can not have Method named "Active"

Open antmanler opened this issue 2 years ago • 2 comments

The following program sample.go triggers an unexpected result

// modified from interp/interp_export_test.go

package interp_test

import (
	"reflect"
	"testing"

	"github.com/traefik/yaegi/interp"
)

type Helloer interface {
	Hello()
	Active() bool
}

func Hi(h Helloer) {
	println("In Hi:")
	h.Hello()
	println("Active: ", h.Active())
}

type Wrap struct {
	IValue interface{}

	WHello func() // related to the Hello() method.
	// Other interface method wrappers...
	WActive func() bool
}

func (w Wrap) Hello() { w.WHello() }

func (w Wrap) Active() bool { return w.WActive() }

func TestInterface(t *testing.T) {
	i := interp.New(interp.Options{})
	// export the Wrap type to the interpreter under virtual "wrap" package
	err := i.Use(interp.Exports{
		"github.com/traefik/yaegi/interp_test/interp_test": {
			"Helloer":  reflect.ValueOf((*Helloer)(nil)),
			"_Helloer": reflect.ValueOf((*Wrap)(nil)),
		},
	})
	if err != nil {
		t.Fatal(err)
	}

	eval(t, i, `
import "github.com/traefik/yaegi/interp_test"

type MyInt int

func (m MyInt) Hello() { println("hello from Myint", m) }

func (m MyInt) Active() bool { return false }

func NewMyInt(i int) interp_test.Helloer {
	m := MyInt(i)
	return m
}
`)
	NewMyInt := eval(t, i, "NewMyInt").Interface().(func(int) Helloer)
	w := NewMyInt(4)
	Hi(w)
}

Expected result

=== RUN   TestInterface
In Hi:
hello from Myint 4
Active:  false
--- PASS: TestInterface (0.00s)
PASS
ok  	github.com/traefik/yaegi/interp	0.011s

Got

=== RUN   TestInterface
11:7: panic
--- FAIL: TestInterface (0.00s)
panic: reflect.Set: value of type func() bool is not assignable to type func() [recovered]
	panic: reflect.Set: value of type func() bool is not assignable to type func() [recovered]
	panic: reflect.Set: value of type func() bool is not assignable to type func()

goroutine 34 [running]:
testing.tRunner.func1.2({0xcfd5c0, 0xc0002071f0})
	/usr/local/go/src/testing/testing.go:1389 +0x24e
testing.tRunner.func1()
	/usr/local/go/src/testing/testing.go:1392 +0x39f
panic({0xcfd5c0, 0xc0002071f0})
	/usr/local/go/src/runtime/panic.go:838 +0x207
github.com/traefik/yaegi/interp.runCfg.func1()
	/workspaces/yaegi/interp/run.go:193 +0x145
panic({0xcfd5c0, 0xc0002071f0})
	/usr/local/go/src/runtime/panic.go:838 +0x207
reflect.Value.assignTo({0xcf8ec0?, 0xc000356a80?, 0xff9c78?}, {0xe239f1, 0xb}, 0xcf4de0, 0x0)
	/usr/local/go/src/reflect/value.go:3062 +0x2ac
reflect.Value.Set({0xcf4de0?, 0xc00020acd0?, 0xd54fa0?}, {0xcf8ec0?, 0xc000356a80?, 0x4fc1be?})
	/usr/local/go/src/reflect/value.go:2088 +0xeb
github.com/traefik/yaegi/interp.genInterfaceWrapper.func1(0xcfc8c0?)
	/workspaces/yaegi/interp/run.go:1108 +0x813
github.com/traefik/yaegi/interp._return.func1(0xc0003480b0)
	/workspaces/yaegi/interp/run.go:2424 +0x22
github.com/traefik/yaegi/interp.runCfg(0xc000352000, 0xc0003480b0, 0xc0002c15c0?, 0xcfc8c0?)
	/workspaces/yaegi/interp/run.go:201 +0x29d
github.com/traefik/yaegi/interp.genFunctionWrapper.func2.1({0xc0002044b0, 0x1, 0x1?})
	/workspaces/yaegi/interp/run.go:1023 +0x4a5
github.com/traefik/yaegi/interp_test.TestInterface(0xc000228680)
	/workspaces/yaegi/interp/interp_export_test.go:115 +0x402
testing.tRunner(0xc000228680, 0xe7d8a8)
	/usr/local/go/src/testing/testing.go:1439 +0x102
created by testing.(*T).Run
	/usr/local/go/src/testing/testing.go:1486 +0x35f
FAIL	github.com/traefik/yaegi/interp	0.013s

Yaegi Version

5665c9a4108e5f878c0d1d8d1e1913eb3c314154

Additional Notes

If I rename Active to IsActive or whatever, it works as expected.

antmanler avatar Apr 14 '22 02:04 antmanler

Any progress on this? This strange issue blocks me export interface with name of Active 😂

antmanler avatar Apr 28 '22 00:04 antmanler

@mvertes Happen to find similar behaviour occurred on macOS, while other platform worked as expected:

On host I export a function like FooWithCallback(func(error) bool), in script call this function with a callback returns false.

FooWithCallback(func(_ error) bool {return false})

FooWithCallback always reads true on macOS

Yaegi Version

v0.11.2 & v0.12.0 go version go1.18.3 darwin/arm64

antmanler avatar Jun 07 '22 10:06 antmanler