}
// 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 {
return true
}
// Composite types.
switch kind {
case Array:
- return T.Elem() == V.Elem() && T.Len() == V.Len()
+ return T.Len() == V.Len() && haveIdenticalType(T.Elem(), V.Elem(), cmpTags)
case Chan:
// Special case:
// x is a bidirectional channel value, T is a channel type,
// 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
}
// 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:
t := (*funcType)(unsafe.Pointer(T))
return false
}
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
}
}
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
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:
- return T.Elem() == V.Elem()
+ return haveIdenticalType(T.Elem(), V.Elem(), cmpTags)
case Struct:
t := (*structType)(unsafe.Pointer(T))
if tf.name.name() != vf.name.name() {
return false
}
- if tf.typ != vf.typ {
+ if !haveIdenticalType(tf.typ, vf.typ, cmpTags) {
return false
}
- if tf.name.tag() != vf.name.tag() {
+ if cmpTags && tf.name.tag() != vf.name.tag() {
return false
}
if tf.offset != vf.offset {
// Look in cache.
funcLookupCache.RLock()
for _, t := range funcLookupCache.m[hash] {
- if haveIdenticalUnderlyingType(&ft.rtype, t) {
+ if haveIdenticalUnderlyingType(&ft.rtype, t, true) {
funcLookupCache.RUnlock()
return t
}
funcLookupCache.m = make(map[uint32][]*rtype)
}
for _, t := range funcLookupCache.m[hash] {
- if haveIdenticalUnderlyingType(&ft.rtype, t) {
+ if haveIdenticalUnderlyingType(&ft.rtype, t, true) {
return t
}
}
// Look in known types for the same string representation.
str := funcStr(ft)
for _, tt := range typesByString(str) {
- if haveIdenticalUnderlyingType(&ft.rtype, tt) {
+ if haveIdenticalUnderlyingType(&ft.rtype, tt, true) {
funcLookupCache.m[hash] = append(funcLookupCache.m[hash], tt)
return tt
}
structLookupCache.RLock()
for _, st := range structLookupCache.m[hash] {
t := st.common()
- if haveIdenticalUnderlyingType(&typ.rtype, t) {
+ if haveIdenticalUnderlyingType(&typ.rtype, t, true) {
structLookupCache.RUnlock()
return t
}
}
for _, st := range structLookupCache.m[hash] {
t := st.common()
- if haveIdenticalUnderlyingType(&typ.rtype, t) {
+ if haveIdenticalUnderlyingType(&typ.rtype, t, true) {
return t
}
}
// Look in known types.
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
// as the 'u uncommonType' field won't be accessed except when
// tflag&tflagUncommon is set.