mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
reflect: ignore struct tags when converting structs
Implementation of spec change https://golang.org/cl/24190/. For #16085. Change-Id: Ib7cb513354269282dfad663c7d2c6e624149f3cd Reviewed-on: https://go-review.googlesource.com/30191 Reviewed-by: David Crawshaw <crawshaw@golang.org>
This commit is contained in:
parent
f5b0012362
commit
ddb77100a6
3 changed files with 63 additions and 19 deletions
|
|
@ -3098,6 +3098,9 @@ func ReadWriterV(x io.ReadWriter) Value {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Empty struct{}
|
type Empty struct{}
|
||||||
|
type MyStruct struct {
|
||||||
|
x int "tag"
|
||||||
|
}
|
||||||
type MyString string
|
type MyString string
|
||||||
type MyBytes []byte
|
type MyBytes []byte
|
||||||
type MyRunes []int32
|
type MyRunes []int32
|
||||||
|
|
@ -3409,6 +3412,35 @@ var convertTests = []struct {
|
||||||
{V((func())(nil)), V(MyFunc(nil))},
|
{V((func())(nil)), V(MyFunc(nil))},
|
||||||
{V((MyFunc)(nil)), V((func())(nil))},
|
{V((MyFunc)(nil)), V((func())(nil))},
|
||||||
|
|
||||||
|
// structs with different tags
|
||||||
|
{V(struct {
|
||||||
|
x int "foo"
|
||||||
|
}{}), V(struct {
|
||||||
|
x int "bar"
|
||||||
|
}{})},
|
||||||
|
|
||||||
|
{V(struct {
|
||||||
|
x int "bar"
|
||||||
|
}{}), V(struct {
|
||||||
|
x int "foo"
|
||||||
|
}{})},
|
||||||
|
|
||||||
|
{V(MyStruct{}), V(struct {
|
||||||
|
x int "foo"
|
||||||
|
}{})},
|
||||||
|
|
||||||
|
{V(struct {
|
||||||
|
x int "foo"
|
||||||
|
}{}), V(MyStruct{})},
|
||||||
|
|
||||||
|
{V(MyStruct{}), V(struct {
|
||||||
|
x int "bar"
|
||||||
|
}{})},
|
||||||
|
|
||||||
|
{V(struct {
|
||||||
|
x int "bar"
|
||||||
|
}{}), V(MyStruct{})},
|
||||||
|
|
||||||
// can convert *byte and *MyByte
|
// can convert *byte and *MyByte
|
||||||
{V((*byte)(nil)), V((*MyByte)(nil))},
|
{V((*byte)(nil)), V((*MyByte)(nil))},
|
||||||
{V((*MyByte)(nil)), V((*byte)(nil))},
|
{V((*MyByte)(nil)), V((*byte)(nil))},
|
||||||
|
|
|
||||||
|
|
@ -1584,10 +1584,22 @@ func directlyAssignable(T, V *rtype) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// x's type T and V must have identical underlying types.
|
// x's type T and V must have identical underlying types.
|
||||||
return haveIdenticalUnderlyingType(T, V)
|
return haveIdenticalUnderlyingType(T, V, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func haveIdenticalUnderlyingType(T, V *rtype) bool {
|
func haveIdenticalType(T, V Type, cmpTags bool) bool {
|
||||||
|
if cmpTags {
|
||||||
|
return T == V
|
||||||
|
}
|
||||||
|
|
||||||
|
if T.Name() != V.Name() || T.Kind() != V.Kind() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return haveIdenticalUnderlyingType(T.common(), V.common(), false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func haveIdenticalUnderlyingType(T, V *rtype, cmpTags bool) bool {
|
||||||
if T == V {
|
if T == V {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
@ -1606,18 +1618,18 @@ func haveIdenticalUnderlyingType(T, V *rtype) bool {
|
||||||
// Composite types.
|
// Composite types.
|
||||||
switch kind {
|
switch kind {
|
||||||
case Array:
|
case Array:
|
||||||
return T.Elem() == V.Elem() && T.Len() == V.Len()
|
return T.Len() == V.Len() && haveIdenticalType(T.Elem(), V.Elem(), cmpTags)
|
||||||
|
|
||||||
case Chan:
|
case Chan:
|
||||||
// Special case:
|
// Special case:
|
||||||
// x is a bidirectional channel value, T is a channel type,
|
// x is a bidirectional channel value, T is a channel type,
|
||||||
// and x's type V and T have identical element types.
|
// and x's type V and T have identical element types.
|
||||||
if V.ChanDir() == BothDir && T.Elem() == V.Elem() {
|
if V.ChanDir() == BothDir && haveIdenticalType(T.Elem(), V.Elem(), cmpTags) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise continue test for identical underlying type.
|
// Otherwise continue test for identical underlying type.
|
||||||
return V.ChanDir() == T.ChanDir() && T.Elem() == V.Elem()
|
return V.ChanDir() == T.ChanDir() && haveIdenticalType(T.Elem(), V.Elem(), cmpTags)
|
||||||
|
|
||||||
case Func:
|
case Func:
|
||||||
t := (*funcType)(unsafe.Pointer(T))
|
t := (*funcType)(unsafe.Pointer(T))
|
||||||
|
|
@ -1626,12 +1638,12 @@ func haveIdenticalUnderlyingType(T, V *rtype) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
for i := 0; i < t.NumIn(); i++ {
|
for i := 0; i < t.NumIn(); i++ {
|
||||||
if t.In(i) != v.In(i) {
|
if !haveIdenticalType(t.In(i), v.In(i), cmpTags) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for i := 0; i < t.NumOut(); i++ {
|
for i := 0; i < t.NumOut(); i++ {
|
||||||
if t.Out(i) != v.Out(i) {
|
if !haveIdenticalType(t.Out(i), v.Out(i), cmpTags) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1648,10 +1660,10 @@ func haveIdenticalUnderlyingType(T, V *rtype) bool {
|
||||||
return false
|
return false
|
||||||
|
|
||||||
case Map:
|
case Map:
|
||||||
return T.Key() == V.Key() && T.Elem() == V.Elem()
|
return haveIdenticalType(T.Key(), V.Key(), cmpTags) && haveIdenticalType(T.Elem(), V.Elem(), cmpTags)
|
||||||
|
|
||||||
case Ptr, Slice:
|
case Ptr, Slice:
|
||||||
return T.Elem() == V.Elem()
|
return haveIdenticalType(T.Elem(), V.Elem(), cmpTags)
|
||||||
|
|
||||||
case Struct:
|
case Struct:
|
||||||
t := (*structType)(unsafe.Pointer(T))
|
t := (*structType)(unsafe.Pointer(T))
|
||||||
|
|
@ -1665,10 +1677,10 @@ func haveIdenticalUnderlyingType(T, V *rtype) bool {
|
||||||
if tf.name.name() != vf.name.name() {
|
if tf.name.name() != vf.name.name() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if tf.typ != vf.typ {
|
if !haveIdenticalType(tf.typ, vf.typ, cmpTags) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if tf.name.tag() != vf.name.tag() {
|
if cmpTags && tf.name.tag() != vf.name.tag() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if tf.offset != vf.offset {
|
if tf.offset != vf.offset {
|
||||||
|
|
@ -2024,7 +2036,7 @@ func FuncOf(in, out []Type, variadic bool) Type {
|
||||||
// Look in cache.
|
// Look in cache.
|
||||||
funcLookupCache.RLock()
|
funcLookupCache.RLock()
|
||||||
for _, t := range funcLookupCache.m[hash] {
|
for _, t := range funcLookupCache.m[hash] {
|
||||||
if haveIdenticalUnderlyingType(&ft.rtype, t) {
|
if haveIdenticalUnderlyingType(&ft.rtype, t, true) {
|
||||||
funcLookupCache.RUnlock()
|
funcLookupCache.RUnlock()
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
@ -2038,7 +2050,7 @@ func FuncOf(in, out []Type, variadic bool) Type {
|
||||||
funcLookupCache.m = make(map[uint32][]*rtype)
|
funcLookupCache.m = make(map[uint32][]*rtype)
|
||||||
}
|
}
|
||||||
for _, t := range funcLookupCache.m[hash] {
|
for _, t := range funcLookupCache.m[hash] {
|
||||||
if haveIdenticalUnderlyingType(&ft.rtype, t) {
|
if haveIdenticalUnderlyingType(&ft.rtype, t, true) {
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2046,7 +2058,7 @@ func FuncOf(in, out []Type, variadic bool) Type {
|
||||||
// Look in known types for the same string representation.
|
// Look in known types for the same string representation.
|
||||||
str := funcStr(ft)
|
str := funcStr(ft)
|
||||||
for _, tt := range typesByString(str) {
|
for _, tt := range typesByString(str) {
|
||||||
if haveIdenticalUnderlyingType(&ft.rtype, tt) {
|
if haveIdenticalUnderlyingType(&ft.rtype, tt, true) {
|
||||||
funcLookupCache.m[hash] = append(funcLookupCache.m[hash], tt)
|
funcLookupCache.m[hash] = append(funcLookupCache.m[hash], tt)
|
||||||
return tt
|
return tt
|
||||||
}
|
}
|
||||||
|
|
@ -2599,7 +2611,7 @@ func StructOf(fields []StructField) Type {
|
||||||
structLookupCache.RLock()
|
structLookupCache.RLock()
|
||||||
for _, st := range structLookupCache.m[hash] {
|
for _, st := range structLookupCache.m[hash] {
|
||||||
t := st.common()
|
t := st.common()
|
||||||
if haveIdenticalUnderlyingType(&typ.rtype, t) {
|
if haveIdenticalUnderlyingType(&typ.rtype, t, true) {
|
||||||
structLookupCache.RUnlock()
|
structLookupCache.RUnlock()
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
@ -2616,14 +2628,14 @@ func StructOf(fields []StructField) Type {
|
||||||
}
|
}
|
||||||
for _, st := range structLookupCache.m[hash] {
|
for _, st := range structLookupCache.m[hash] {
|
||||||
t := st.common()
|
t := st.common()
|
||||||
if haveIdenticalUnderlyingType(&typ.rtype, t) {
|
if haveIdenticalUnderlyingType(&typ.rtype, t, true) {
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look in known types.
|
// Look in known types.
|
||||||
for _, t := range typesByString(str) {
|
for _, t := range typesByString(str) {
|
||||||
if haveIdenticalUnderlyingType(&typ.rtype, t) {
|
if haveIdenticalUnderlyingType(&typ.rtype, t, true) {
|
||||||
// even if 't' wasn't a structType with methods, we should be ok
|
// even if 't' wasn't a structType with methods, we should be ok
|
||||||
// as the 'u uncommonType' field won't be accessed except when
|
// as the 'u uncommonType' field won't be accessed except when
|
||||||
// tflag&tflagUncommon is set.
|
// tflag&tflagUncommon is set.
|
||||||
|
|
|
||||||
|
|
@ -2239,14 +2239,14 @@ func convertOp(dst, src *rtype) func(Value, Type) Value {
|
||||||
}
|
}
|
||||||
|
|
||||||
// dst and src have same underlying type.
|
// dst and src have same underlying type.
|
||||||
if haveIdenticalUnderlyingType(dst, src) {
|
if haveIdenticalUnderlyingType(dst, src, false) {
|
||||||
return cvtDirect
|
return cvtDirect
|
||||||
}
|
}
|
||||||
|
|
||||||
// dst and src are unnamed pointer types with same underlying base type.
|
// dst and src are unnamed pointer types with same underlying base type.
|
||||||
if dst.Kind() == Ptr && dst.Name() == "" &&
|
if dst.Kind() == Ptr && dst.Name() == "" &&
|
||||||
src.Kind() == Ptr && src.Name() == "" &&
|
src.Kind() == Ptr && src.Name() == "" &&
|
||||||
haveIdenticalUnderlyingType(dst.Elem().common(), src.Elem().common()) {
|
haveIdenticalUnderlyingType(dst.Elem().common(), src.Elem().common(), false) {
|
||||||
return cvtDirect
|
return cvtDirect
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue