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