package main
import (
"reflect"
)
type Getter interface{ Get() int }
type Incer interface{ Inc() }
type T struct{ x int }
func (p T) Get() int { return p.x }
func (p *T) Inc() { p.x++ }
func main() {
CompilerVersion_ValueField() // This does not panic.
ReflectVersion_ValueField() // This panics.
// Two cases that both work. The embedded field is a pointer type.
// CompilerVersion_PointerField() // This does not panic.
// ReflectVersion_PointerField() // This also does not panic.
}
func CompilerVersion_ValueField() {
var rv2 struct{ T }
(&rv2).T.Inc() // All
(&(rv2.T)).Inc() // four
(&rv2).Inc() // compile.
rv2.Inc() // From spec : If x is addressable and &x's method set contains m, x.m() is shorthand for (&x).m().
var i interface{} = &rv2
_ = i.(Getter).Get()
// This does not panic, despite the embedded field T not being a pointer.
i.(Incer).Inc()
}
func ReflectVersion_ValueField() {
// This does not help. Comment at top of #15924 not withstanding.
// var _ interface{} = new(struct {
// T
// })
rt := reflect.StructOf([]reflect.StructField{
{
Name: "Field0",
Anonymous: true, // define T to be embedded
Type: reflect.TypeOf(T{}),
},
})
rv2 := reflect.New(rt).Elem()
_ = rv2.Interface().(Getter).Get() // go1.[78] panics here, go1.9+ does not
// go1.13 panics. Inc wasn't wrapped for this StructOf value, presumably because the field was not a pointer.
_ = rv2.Interface().(Incer) // <- go1.9+ panic: missing method Inc
}
// func CompilerVersion_PointerField() {
//
// var rv1 struct {
// *T
// }
// var i interface{} = &rv1
//
// // Expect Get and Inc to panic while pointer is still nil.
//
// shouldPanic(func() {
// _ = i.(Getter).Get()
// })
// shouldPanic(func() {
// i.(Incer).Inc()
// })
//
// rv1.T = &T{}
//
// // Expect Get and Inc to no longer panic.
// _ = i.(Getter).Get()
// i.(Incer).Inc()
// }
//
// func ReflectVersion_PointerField() {
//
// rt := reflect.StructOf([]reflect.StructField{
// {
// Name: "Field0",
// Anonymous: true,
// Type: reflect.PtrTo(reflect.TypeOf(T{})),
// },
// })
// rv1 := reflect.New(rt).Elem()
//
// // Expect Get and Inc to panic while pointer is still nil.
//
// shouldPanic(func() {
// _ = rv1.Interface().(Getter).Get()
// })
// shouldPanic(func() {
// rv1.Interface().(Incer).Inc()
// })
//
// rv1.Field(0).Set(reflect.ValueOf(func() interface{} {
// v := T{0}
// return &v
// }()))
//
// // Expect Get and Inc to no longer panic.
// _ = rv1.Interface().(Getter).Get()
// rv1.Interface().(Incer).Inc()
// }
//
// func shouldPanic(f func()) {
// defer func() {
// if recover() == nil {
// panic("did not panic")
// }
// }()
// f()
// }