yaegi icon indicating copy to clipboard operation
yaegi copied to clipboard

reflect.MethodByName always panics

Open gsora opened this issue 5 years ago • 3 comments

The following program sample.go triggers a panic:

package main

import (
	"github.com/containous/yaegi/interp"
	"github.com/containous/yaegi/stdlib"
)

var a = `
package main
import (
	"fmt"
	"reflect"
)


type f struct{}
func (fb *f) One() { fmt.Println("1") }
func Do() {
	var fb f
	reflect.ValueOf(&fb).MethodByName("One").Call([]reflect.Value{})
}

`

func main() {

	i := interp.New(interp.Options{})
	i.Use(stdlib.Symbols)

	src := a
	_, err := i.Eval(src)
	if err != nil {
		panic(err)
	}
	v, err := i.Eval("main.Do")
	if err != nil {
		panic(err)
	}

	bar := v.Interface().(func())
	bar()
}

Expected result:

$ go run ./sample.go
1

Got:

$ yaegi ./sample.go
12:6: panic
panic: reflect: call of reflect.Value.Call on zero Value [recovered]
	panic: reflect: call of reflect.Value.Call on zero Value

goroutine 1 [running]:
github.com/containous/yaegi/interp.runCfg.func1(0xc0003380a0, 0xc000340500)
	/Users/gsora/Go/pkg/mod/github.com/containous/[email protected]/interp/run.go:119 +0x20c
panic(0x18e8260, 0xc0002054c0)
	/usr/local/Cellar/go/1.14.4/libexec/src/runtime/panic.go:969 +0x166
reflect.flag.mustBe(...)
	/usr/local/Cellar/go/1.14.4/libexec/src/reflect/value.go:208
reflect.Value.Call(0x0, 0x0, 0x0, 0x21c6d58, 0x0, 0x0, 0x219ae60, 0xc00022f818, 0x1018cd3)
	/usr/local/Cellar/go/1.14.4/libexec/src/reflect/value.go:319 +0x16d
reflect.Value.call(0x19d7980, 0xc000205300, 0xe93, 0x19d9fb5, 0x4, 0xc000205480, 0x1, 0x1, 0x18, 0xc000205480, ...)
	/usr/local/Cellar/go/1.14.4/libexec/src/reflect/value.go:460 +0x8ab
reflect.Value.Call(0x19d7980, 0xc000205300, 0xe93, 0xc000205480, 0x1, 0x1, 0x19d7980, 0x1, 0xc000205480)
	/usr/local/Cellar/go/1.14.4/libexec/src/reflect/value.go:321 +0xb4
github.com/containous/yaegi/interp.callBin.func1(0x19d7980, 0xc000205300, 0xe93, 0xc000205480, 0x1, 0x1, 0xc000205460, 0x97, 0x97)
	/Users/gsora/Go/pkg/mod/github.com/containous/[email protected]/interp/run.go:1077 +0x64
github.com/containous/yaegi/interp.callBin.func10(0xc0003380a0, 0xc000216280)
	/Users/gsora/Go/pkg/mod/github.com/containous/[email protected]/interp/run.go:1218 +0x1c2
github.com/containous/yaegi/interp.runCfg(0xc000340500, 0xc0003380a0)
	/Users/gsora/Go/pkg/mod/github.com/containous/[email protected]/interp/run.go:125 +0x6d
github.com/containous/yaegi/interp.genFunctionWrapper.func2.1(0x21c6d58, 0x0, 0x0, 0x21c6d58, 0xc00031ccf0, 0x18a6720)
	/Users/gsora/Go/pkg/mod/github.com/containous/[email protected]/interp/run.go:709 +0x3ca
reflect.callReflect(0xc00031cde0, 0xc00022ff30, 0xc00022ff18)
	/usr/local/Cellar/go/1.14.4/libexec/src/reflect/value.go:549 +0x322
reflect.makeFuncStub(0x18a6720, 0xc00031cde0, 0x13, 0x18a6701, 0x18a6720, 0xc00031cde0, 0x0, 0x0, 0xc0002421a0, 0xc00022ffd0, ...)
	/usr/local/Cellar/go/1.14.4/libexec/src/reflect/asm_amd64.s:20 +0x42
main.main()
	/Users/gsora/Documents/stuff/t/main.go:41 +0x120
exit status 2

gsora avatar Sep 13 '20 12:09 gsora

The reflect package from stdlib doesn't allow to create methods on types. This feature is emulated in yaegi. As a result, there is no method visible by reflect, thus the panic. This may improve in the future when reflect allows to create methods.

mvertes avatar Sep 23 '20 15:09 mvertes

@gsora out of curiosity, is this limitation an actual blocker for you? Because in the sample you gave us, you could of course replace:

reflect.ValueOf(&fb).MethodByName("One").Call([]reflect.Value{})

with:

f.One()

and that would work, right? so, while we acknowledge the limitation, we also can't tell from the sample if you're hitting an actual problem, or if you're reporting the bug just to be a good "open-source citizen" ;)

mpl avatar Sep 23 '20 15:09 mpl

Because in the sample you gave us, you could of course replace: reflect.ValueOf(&fb).MethodByName("One").Call([]reflect.Value{})

It would work indeed!

I was trying to write a piece of code that "generated" struct methods and then called them dynamically via reflect.

It was mostly an exercise, nothing that ended up blocking a feature.

you're reporting the bug just to be a good "open-source citizen"

Yes, exactly this :)

gsora avatar Sep 23 '20 15:09 gsora