Source file
src/go/types/hash.go
1
2
3
4
5 package types
6
7
8
9 import (
10 "fmt"
11 "hash/maphash"
12 )
13
14 type (
15
16
17
18 Hasher struct{}
19
20
21
22 HasherIgnoreTags struct{}
23 )
24
25 var (
26 _ maphash.Hasher[Type] = Hasher{}
27 _ maphash.Hasher[Type] = HasherIgnoreTags{}
28 )
29
30 func (Hasher) Hash(h *maphash.Hash, t Type) {
31
32
33
34
35 h.WriteByte(0)
36 hasher{inGenericSig: false}.hash(h, t)
37 }
38 func (HasherIgnoreTags) Hash(h *maphash.Hash, t Type) {
39 h.WriteByte(1)
40 hasher{inGenericSig: false}.hash(h, t)
41 }
42
43 func (Hasher) Equal(x, y Type) bool { return Identical(x, y) }
44 func (HasherIgnoreTags) Equal(x, y Type) bool { return IdenticalIgnoreTags(x, y) }
45
46
47
48
49 type hasher struct{ inGenericSig bool }
50
51 func (hr hasher) hash(h *maphash.Hash, t Type) {
52
53 switch t := t.(type) {
54 case *Alias:
55 hr.hash(h, Unalias(t))
56
57 case *Array:
58 h.WriteByte('A')
59 maphash.WriteComparable(h, t.Len())
60 hr.hash(h, t.Elem())
61
62 case *Basic:
63 h.WriteByte('B')
64 h.WriteByte(byte(t.Kind()))
65
66 case *Chan:
67 h.WriteByte('C')
68 h.WriteByte(byte(t.Dir()))
69 hr.hash(h, t.Elem())
70
71 case *Interface:
72 h.WriteByte('I')
73 h.WriteByte(byte(t.NumMethods()))
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88 var hash uint64
89 for m := range t.Methods() {
90 var subh maphash.Hash
91 subh.SetSeed(h.Seed())
92
93
94
95 subh.WriteString(m.Name())
96 hr.shallowHash(&subh, m.Type())
97 hash ^= subh.Sum64()
98 }
99 maphash.WriteComparable(h, hash)
100
101
102
103
104
105
106 case *Map:
107 h.WriteByte('M')
108 hr.hash(h, t.Key())
109 hr.hash(h, t.Elem())
110
111 case *Named:
112 h.WriteByte('N')
113 hr.hashTypeName(h, t.Obj())
114 for targ := range t.TypeArgs().Types() {
115 hr.hash(h, targ)
116 }
117
118 case *Pointer:
119 h.WriteByte('P')
120 hr.hash(h, t.Elem())
121
122 case *Signature:
123 h.WriteByte('F')
124 maphash.WriteComparable(h, t.Variadic())
125 tparams := t.TypeParams()
126 if n := tparams.Len(); n > 0 {
127 hr.inGenericSig = true
128
129 maphash.WriteComparable(h, n)
130 for tparam := range tparams.TypeParams() {
131 hr.hash(h, tparam.Constraint())
132 }
133 }
134 hr.hashTuple(h, t.Params())
135 hr.hashTuple(h, t.Results())
136
137 case *Slice:
138 h.WriteByte('S')
139 hr.hash(h, t.Elem())
140
141 case *Struct:
142 h.WriteByte('R')
143 n := t.NumFields()
144 h.WriteByte(byte(n))
145 for i := range n {
146 f := t.Field(i)
147 maphash.WriteComparable(h, f.Anonymous())
148
149
150 h.WriteString(f.Name())
151 hr.hash(h, f.Type())
152 }
153
154 case *Tuple:
155 hr.hashTuple(h, t)
156
157 case *TypeParam:
158 hr.hashTypeParam(h, t)
159
160 case *Union:
161 h.WriteByte('U')
162
163
164
165
166 default:
167 panic(fmt.Sprintf("%T: %v", t, t))
168 }
169 }
170
171 func (hr hasher) hashTuple(h *maphash.Hash, t *Tuple) {
172 h.WriteByte('T')
173 h.WriteByte(byte(t.Len()))
174 for v := range t.Variables() {
175 hr.hash(h, v.Type())
176 }
177 }
178
179
180
181
182
183
184
185
186
187
188
189 func (hr hasher) hashTypeParam(h *maphash.Hash, t *TypeParam) {
190 h.WriteByte('P')
191
192
193
194
195
196
197
198
199
200 if !hr.inGenericSig {
201
202
203 hr.hashTypeName(h, t.Obj())
204 } else {
205 h.WriteByte(byte(t.Index()))
206 }
207 }
208
209
210 func (hasher) hashTypeName(h *maphash.Hash, tname *TypeName) {
211 h.WriteByte('N')
212
213
214 maphash.WriteComparable(h, tname)
215 }
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231 func (hr hasher) shallowHash(h *maphash.Hash, t Type) {
232
233
234
235
236 switch t := t.(type) {
237 case *Alias:
238 hr.shallowHash(h, Unalias(t))
239
240 case *Array:
241 h.WriteByte('A')
242 maphash.WriteComparable(h, t.Len())
243
244
245 case *Basic:
246 h.WriteByte('B')
247 h.WriteByte(byte(t.Kind()))
248
249 case *Chan:
250 h.WriteByte('C')
251
252
253 case *Interface:
254 h.WriteByte('I')
255
256
257 case *Map:
258 h.WriteByte('M')
259
260
261 case *Named:
262 hr.hashTypeName(h, t.Obj())
263
264 case *Pointer:
265 h.WriteByte('P')
266
267
268 case *Signature:
269 h.WriteByte(byte(btoi(t.Variadic())))
270
271
272 hr.shallowHash(h, t.Params())
273 hr.shallowHash(h, t.Results())
274
275 case *Slice:
276 h.WriteByte('S')
277
278
279 case *Struct:
280 h.WriteByte('R')
281 h.WriteByte(byte(t.NumFields()))
282
283
284 case *Tuple:
285 h.WriteByte('T')
286 h.WriteByte(byte(t.Len()))
287 for v := range t.Variables() {
288 hr.shallowHash(h, v.Type())
289 }
290
291 case *TypeParam:
292 hr.hashTypeParam(h, t)
293
294 case *Union:
295 h.WriteByte('U')
296
297
298 default:
299 panic(fmt.Sprintf("shallowHash: %T: %v", t, t))
300 }
301 }
302
303 func btoi(b bool) int {
304 if b {
305 return 1
306 } else {
307 return 0
308 }
309 }
310
View as plain text