diff --git a/src/reflect/value.go b/src/reflect/value.go index f5f0132d..10cf4f74 100644 --- a/src/reflect/value.go +++ b/src/reflect/value.go @@ -67,6 +67,14 @@ func (v Value) Interface() interface{} { // valueInterfaceUnsafe is used by the runtime to hash map keys. It should not // be subject to the isExported check. func valueInterfaceUnsafe(v Value) interface{} { + if v.typecode.Kind() == Interface { + // The value itself is an interface. This can happen when getting the + // value of a struct field of interface type, like this: + // type T struct { + // X interface{} + // } + return *(*interface{})(v.value) + } if v.isIndirect() && v.typecode.Size() <= unsafe.Sizeof(uintptr(0)) { // Value was indirect but must be put back directly in the interface // value. diff --git a/testdata/reflect.go b/testdata/reflect.go index 5a107e2d..2b7dbc04 100644 --- a/testdata/reflect.go +++ b/testdata/reflect.go @@ -321,6 +321,9 @@ func main() { println("\nstruct tags") TestStructTag() + + println("\nv.Interface() method") + testInterfaceMethod() } func emptyFunc() { @@ -470,6 +473,19 @@ func TestStructTag() { println(field.Tag.Get("color"), field.Tag.Get("species")) } +// Test Interface() call: it should never return an interface itself. +func testInterfaceMethod() { + v := reflect.ValueOf(struct{ X interface{} }{X: 5}) + println("kind:", v.Field(0).Kind().String()) + itf := v.Field(0).Interface() + switch n := itf.(type) { + case int: + println("int", n) // correct + default: + println("something else") // incorrect + } +} + var xorshift32State uint32 = 1 func xorshift32(x uint32) uint32 { diff --git a/testdata/reflect.txt b/testdata/reflect.txt index 4bd55fd8..19642949 100644 --- a/testdata/reflect.txt +++ b/testdata/reflect.txt @@ -377,3 +377,7 @@ type assertion succeeded for unreferenced type struct tags blue gopher + +v.Interface() method +kind: interface +int 5