1
2
3
4
5 package types
6
7 const (
8 identIgnoreTags = 1 << iota
9 identStrict
10 )
11
12
13
14
15
16
17 func Identical(t1, t2 *Type) bool {
18 return identical(t1, t2, 0, nil)
19 }
20
21
22
23 func IdenticalIgnoreTags(t1, t2 *Type) bool {
24 return identical(t1, t2, identIgnoreTags, nil)
25 }
26
27
28
29 func IdenticalStrict(t1, t2 *Type) bool {
30 return identical(t1, t2, identStrict, nil)
31 }
32
33 type typePair struct {
34 t1 *Type
35 t2 *Type
36 }
37
38 func identical(t1, t2 *Type, flags int, assumedEqual map[typePair]struct{}) bool {
39 if t1 == t2 {
40 return true
41 }
42 if t1 == nil || t2 == nil || t1.kind != t2.kind || t1.Broke() || t2.Broke() {
43 return false
44 }
45 if t1.sym != nil || t2.sym != nil {
46 if flags&identStrict == 0 && (t1.HasShape() || t2.HasShape()) {
47 switch t1.kind {
48 case TINT8, TUINT8, TINT16, TUINT16, TINT32, TUINT32, TINT64, TUINT64, TINT, TUINT, TUINTPTR, TCOMPLEX64, TCOMPLEX128, TFLOAT32, TFLOAT64, TBOOL, TSTRING, TPTR, TUNSAFEPTR:
49 return true
50 }
51
52 goto cont
53 }
54
55
56 switch t1.kind {
57 case TUINT8:
58 return (t1 == Types[TUINT8] || t1 == ByteType) && (t2 == Types[TUINT8] || t2 == ByteType)
59 case TINT32:
60 return (t1 == Types[TINT32] || t1 == RuneType) && (t2 == Types[TINT32] || t2 == RuneType)
61 case TINTER:
62
63
64 isUnnamedEface := func(t *Type) bool { return t.IsEmptyInterface() && t.Sym() == nil }
65 if flags&identStrict != 0 {
66 return t1 == AnyType && isUnnamedEface(t2) && !t2.HasShape() || t2 == AnyType && isUnnamedEface(t1) && !t1.HasShape()
67 }
68 return t1 == AnyType && isUnnamedEface(t2) || t2 == AnyType && isUnnamedEface(t1)
69 default:
70 return false
71 }
72 }
73 cont:
74
75
76
77
78
79 if assumedEqual == nil {
80 assumedEqual = make(map[typePair]struct{})
81 } else if _, ok := assumedEqual[typePair{t1, t2}]; ok {
82 return true
83 }
84 assumedEqual[typePair{t1, t2}] = struct{}{}
85
86 switch t1.kind {
87 case TIDEAL:
88
89
90
91
92 return true
93
94 case TINTER:
95 if t1.AllMethods().Len() != t2.AllMethods().Len() {
96 return false
97 }
98 for i, f1 := range t1.AllMethods().Slice() {
99 f2 := t2.AllMethods().Index(i)
100 if f1.Sym != f2.Sym || !identical(f1.Type, f2.Type, flags, assumedEqual) {
101 return false
102 }
103 }
104 return true
105
106 case TSTRUCT:
107 if t1.NumFields() != t2.NumFields() {
108 return false
109 }
110 for i, f1 := range t1.FieldSlice() {
111 f2 := t2.Field(i)
112 if f1.Sym != f2.Sym || f1.Embedded != f2.Embedded || !identical(f1.Type, f2.Type, flags, assumedEqual) {
113 return false
114 }
115 if (flags&identIgnoreTags) == 0 && f1.Note != f2.Note {
116 return false
117 }
118 }
119 return true
120
121 case TFUNC:
122
123
124
125 for _, f := range ParamsResults {
126
127 fs1, fs2 := f(t1).FieldSlice(), f(t2).FieldSlice()
128 if len(fs1) != len(fs2) {
129 return false
130 }
131 for i, f1 := range fs1 {
132 f2 := fs2[i]
133 if f1.IsDDD() != f2.IsDDD() || !identical(f1.Type, f2.Type, flags, assumedEqual) {
134 return false
135 }
136 }
137 }
138 return true
139
140 case TARRAY:
141 if t1.NumElem() != t2.NumElem() {
142 return false
143 }
144
145 case TCHAN:
146 if t1.ChanDir() != t2.ChanDir() {
147 return false
148 }
149
150 case TMAP:
151 if !identical(t1.Key(), t2.Key(), flags, assumedEqual) {
152 return false
153 }
154 }
155
156 return identical(t1.Elem(), t2.Elem(), flags, assumedEqual)
157 }
158
View as plain text