reflect: StructOf isn't behaving properly with methods on embedded structs
jonbodner opened this issue · 9 comments
Please answer these questions before submitting your issue. Thanks!
What version of Go are you using (go version
)?
1.8.3
What operating system and processor architecture are you using (go env
)?
Visible on Go Playground and on Mac OS
$ go env
GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/mbh475/go_projects"
GORACE=""
GOROOT="/usr/local/go"
GOTOOLDIR="/usr/local/go/pkg/tool/darwin_amd64"
GCCGO="gccgo"
CC="clang"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/xf/5x4cmml91xn880l6v0c9l1dxnrqmjk/T/go-build686415997=/tmp/go-build -gno-record-gcc-switches -fno-common"
CXX="clang++"
CGO_ENABLED="1"
PKG_CONFIG="pkg-config"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
What did you do?
I wrote a small example to show the difference between delegating a method call to an embedded struct normally and doing so via reflection using reflect.StructOf. I expected that embedding via reflection would not work, and would panic at runtime when I tried to cast the Interface(). What happened instead is that I was able to not only cast successfully, I could invoke the method and it would use data in a different embedded struct field.
Links:
Two links, one with two embedded structs, where it's exposing the method from the second struct and using the value from the first struct:
https://play.golang.org/p/TWApy-JibG
The second has one embedded struct, one embedded pointer to a struct, again the method from the second is being used with the data from the first, but this time the data is a string not an int:
https://play.golang.org/p/Dq9Y8DAkvA
What did you expect to see?
In both cases, I expected a panic when I tried to cast the generated struct to the interface that's implemented by the embedded struct.
What did you see instead?
Not only did the cast work, but invoking the method worked as well. In the second case, it's multiplying a string by 2 and producing a nonsense result.
Out of curiosity, have you tried Go 1.9beta2?
Actually, I just tested.
In both examples, with Go 1.9beta2 I get:
panic: reflect.StructOf: field 0 has no name
goroutine 1 [running]:
reflect.StructOf(0xc420041e38, 0x3, 0x3, 0x0, 0x0)
/home/bradfitz/go/src/reflect/type.go:2401 +0x3404
main.main()
/home/bradfitz/reflect1.go:50 +0x562
exit status 2
So maybe this is fixed. I haven't read the repro code in detail yet.
@jonbodner, is Go 1.9's behavior what you expect?
From #20632 (comment):
The current situation is that it sometimes works and sometimes doesn't. Try adding another field to your
StructOf
call, such that the interface is not the first field. Horrible things will happen.
I was a little curious about where the value for f.A
was coming from (in the bar2impl.Double
call), after playing around with the order of the fields in the StructOf
call, it appears that it's coming from the first field of the first element (i.e. Baz.D
in your examples). What's even weirder is that attempting to print either f
or f.B
in the call results in a panic, but f.A
can be printed just fine.
CL https://golang.org/cl/47035 mentions this issue.