github.com/jhump/golang-x-tools@v0.0.0-20220218190644-4958d6d39439/go/types/typeutil/map.go (about) 1 // Copyright 2014 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package typeutil defines various utilities for types, such as Map, 6 // a mapping from types.Type to interface{} values. 7 package typeutil // import "github.com/jhump/golang-x-tools/go/types/typeutil" 8 9 import ( 10 "bytes" 11 "fmt" 12 "go/types" 13 "reflect" 14 15 "github.com/jhump/golang-x-tools/internal/typeparams" 16 ) 17 18 // Map is a hash-table-based mapping from types (types.Type) to 19 // arbitrary interface{} values. The concrete types that implement 20 // the Type interface are pointers. Since they are not canonicalized, 21 // == cannot be used to check for equivalence, and thus we cannot 22 // simply use a Go map. 23 // 24 // Just as with map[K]V, a nil *Map is a valid empty map. 25 // 26 // Not thread-safe. 27 // 28 type Map struct { 29 hasher Hasher // shared by many Maps 30 table map[uint32][]entry // maps hash to bucket; entry.key==nil means unused 31 length int // number of map entries 32 } 33 34 // entry is an entry (key/value association) in a hash bucket. 35 type entry struct { 36 key types.Type 37 value interface{} 38 } 39 40 // SetHasher sets the hasher used by Map. 41 // 42 // All Hashers are functionally equivalent but contain internal state 43 // used to cache the results of hashing previously seen types. 44 // 45 // A single Hasher created by MakeHasher() may be shared among many 46 // Maps. This is recommended if the instances have many keys in 47 // common, as it will amortize the cost of hash computation. 48 // 49 // A Hasher may grow without bound as new types are seen. Even when a 50 // type is deleted from the map, the Hasher never shrinks, since other 51 // types in the map may reference the deleted type indirectly. 52 // 53 // Hashers are not thread-safe, and read-only operations such as 54 // Map.Lookup require updates to the hasher, so a full Mutex lock (not a 55 // read-lock) is require around all Map operations if a shared 56 // hasher is accessed from multiple threads. 57 // 58 // If SetHasher is not called, the Map will create a private hasher at 59 // the first call to Insert. 60 // 61 func (m *Map) SetHasher(hasher Hasher) { 62 m.hasher = hasher 63 } 64 65 // Delete removes the entry with the given key, if any. 66 // It returns true if the entry was found. 67 // 68 func (m *Map) Delete(key types.Type) bool { 69 if m != nil && m.table != nil { 70 hash := m.hasher.Hash(key) 71 bucket := m.table[hash] 72 for i, e := range bucket { 73 if e.key != nil && types.Identical(key, e.key) { 74 // We can't compact the bucket as it 75 // would disturb iterators. 76 bucket[i] = entry{} 77 m.length-- 78 return true 79 } 80 } 81 } 82 return false 83 } 84 85 // At returns the map entry for the given key. 86 // The result is nil if the entry is not present. 87 // 88 func (m *Map) At(key types.Type) interface{} { 89 if m != nil && m.table != nil { 90 for _, e := range m.table[m.hasher.Hash(key)] { 91 if e.key != nil && types.Identical(key, e.key) { 92 return e.value 93 } 94 } 95 } 96 return nil 97 } 98 99 // Set sets the map entry for key to val, 100 // and returns the previous entry, if any. 101 func (m *Map) Set(key types.Type, value interface{}) (prev interface{}) { 102 if m.table != nil { 103 hash := m.hasher.Hash(key) 104 bucket := m.table[hash] 105 var hole *entry 106 for i, e := range bucket { 107 if e.key == nil { 108 hole = &bucket[i] 109 } else if types.Identical(key, e.key) { 110 prev = e.value 111 bucket[i].value = value 112 return 113 } 114 } 115 116 if hole != nil { 117 *hole = entry{key, value} // overwrite deleted entry 118 } else { 119 m.table[hash] = append(bucket, entry{key, value}) 120 } 121 } else { 122 if m.hasher.memo == nil { 123 m.hasher = MakeHasher() 124 } 125 hash := m.hasher.Hash(key) 126 m.table = map[uint32][]entry{hash: {entry{key, value}}} 127 } 128 129 m.length++ 130 return 131 } 132 133 // Len returns the number of map entries. 134 func (m *Map) Len() int { 135 if m != nil { 136 return m.length 137 } 138 return 0 139 } 140 141 // Iterate calls function f on each entry in the map in unspecified order. 142 // 143 // If f should mutate the map, Iterate provides the same guarantees as 144 // Go maps: if f deletes a map entry that Iterate has not yet reached, 145 // f will not be invoked for it, but if f inserts a map entry that 146 // Iterate has not yet reached, whether or not f will be invoked for 147 // it is unspecified. 148 // 149 func (m *Map) Iterate(f func(key types.Type, value interface{})) { 150 if m != nil { 151 for _, bucket := range m.table { 152 for _, e := range bucket { 153 if e.key != nil { 154 f(e.key, e.value) 155 } 156 } 157 } 158 } 159 } 160 161 // Keys returns a new slice containing the set of map keys. 162 // The order is unspecified. 163 func (m *Map) Keys() []types.Type { 164 keys := make([]types.Type, 0, m.Len()) 165 m.Iterate(func(key types.Type, _ interface{}) { 166 keys = append(keys, key) 167 }) 168 return keys 169 } 170 171 func (m *Map) toString(values bool) string { 172 if m == nil { 173 return "{}" 174 } 175 var buf bytes.Buffer 176 fmt.Fprint(&buf, "{") 177 sep := "" 178 m.Iterate(func(key types.Type, value interface{}) { 179 fmt.Fprint(&buf, sep) 180 sep = ", " 181 fmt.Fprint(&buf, key) 182 if values { 183 fmt.Fprintf(&buf, ": %q", value) 184 } 185 }) 186 fmt.Fprint(&buf, "}") 187 return buf.String() 188 } 189 190 // String returns a string representation of the map's entries. 191 // Values are printed using fmt.Sprintf("%v", v). 192 // Order is unspecified. 193 // 194 func (m *Map) String() string { 195 return m.toString(true) 196 } 197 198 // KeysString returns a string representation of the map's key set. 199 // Order is unspecified. 200 // 201 func (m *Map) KeysString() string { 202 return m.toString(false) 203 } 204 205 //////////////////////////////////////////////////////////////////////// 206 // Hasher 207 208 // A Hasher maps each type to its hash value. 209 // For efficiency, a hasher uses memoization; thus its memory 210 // footprint grows monotonically over time. 211 // Hashers are not thread-safe. 212 // Hashers have reference semantics. 213 // Call MakeHasher to create a Hasher. 214 type Hasher struct { 215 memo map[types.Type]uint32 216 217 // ptrMap records pointer identity. 218 ptrMap map[interface{}]uint32 219 220 // sigTParams holds type parameters from the signature being hashed. 221 // Signatures are considered identical modulo renaming of type parameters, so 222 // within the scope of a signature type the identity of the signature's type 223 // parameters is just their index. 224 // 225 // Since the language does not currently support referring to uninstantiated 226 // generic types or functions, and instantiated signatures do not have type 227 // parameter lists, we should never encounter a second non-empty type 228 // parameter list when hashing a generic signature. 229 sigTParams *typeparams.TypeParamList 230 } 231 232 // MakeHasher returns a new Hasher instance. 233 func MakeHasher() Hasher { 234 return Hasher{ 235 memo: make(map[types.Type]uint32), 236 ptrMap: make(map[interface{}]uint32), 237 sigTParams: nil, 238 } 239 } 240 241 // Hash computes a hash value for the given type t such that 242 // Identical(t, t') => Hash(t) == Hash(t'). 243 func (h Hasher) Hash(t types.Type) uint32 { 244 hash, ok := h.memo[t] 245 if !ok { 246 hash = h.hashFor(t) 247 h.memo[t] = hash 248 } 249 return hash 250 } 251 252 // hashString computes the Fowler–Noll–Vo hash of s. 253 func hashString(s string) uint32 { 254 var h uint32 255 for i := 0; i < len(s); i++ { 256 h ^= uint32(s[i]) 257 h *= 16777619 258 } 259 return h 260 } 261 262 // hashFor computes the hash of t. 263 func (h Hasher) hashFor(t types.Type) uint32 { 264 // See Identical for rationale. 265 switch t := t.(type) { 266 case *types.Basic: 267 return uint32(t.Kind()) 268 269 case *types.Array: 270 return 9043 + 2*uint32(t.Len()) + 3*h.Hash(t.Elem()) 271 272 case *types.Slice: 273 return 9049 + 2*h.Hash(t.Elem()) 274 275 case *types.Struct: 276 var hash uint32 = 9059 277 for i, n := 0, t.NumFields(); i < n; i++ { 278 f := t.Field(i) 279 if f.Anonymous() { 280 hash += 8861 281 } 282 hash += hashString(t.Tag(i)) 283 hash += hashString(f.Name()) // (ignore f.Pkg) 284 hash += h.Hash(f.Type()) 285 } 286 return hash 287 288 case *types.Pointer: 289 return 9067 + 2*h.Hash(t.Elem()) 290 291 case *types.Signature: 292 var hash uint32 = 9091 293 if t.Variadic() { 294 hash *= 8863 295 } 296 297 // Use a separate hasher for types inside of the signature, where type 298 // parameter identity is modified to be (index, constraint). We must use a 299 // new memo for this hasher as type identity may be affected by this 300 // masking. For example, in func[T any](*T), the identity of *T depends on 301 // whether we are mapping the argument in isolation, or recursively as part 302 // of hashing the signature. 303 // 304 // We should never encounter a generic signature while hashing another 305 // generic signature, but defensively set sigTParams only if h.mask is 306 // unset. 307 tparams := typeparams.ForSignature(t) 308 if h.sigTParams == nil && tparams.Len() != 0 { 309 h = Hasher{ 310 // There may be something more efficient than discarding the existing 311 // memo, but it would require detecting whether types are 'tainted' by 312 // references to type parameters. 313 memo: make(map[types.Type]uint32), 314 // Re-using ptrMap ensures that pointer identity is preserved in this 315 // hasher. 316 ptrMap: h.ptrMap, 317 sigTParams: tparams, 318 } 319 } 320 321 for i := 0; i < tparams.Len(); i++ { 322 tparam := tparams.At(i) 323 hash += 7 * h.Hash(tparam.Constraint()) 324 } 325 326 return hash + 3*h.hashTuple(t.Params()) + 5*h.hashTuple(t.Results()) 327 328 case *typeparams.Union: 329 return h.hashUnion(t) 330 331 case *types.Interface: 332 // Interfaces are identical if they have the same set of methods, with 333 // identical names and types, and they have the same set of type 334 // restrictions. See go/types.identical for more details. 335 var hash uint32 = 9103 336 337 // Hash methods. 338 for i, n := 0, t.NumMethods(); i < n; i++ { 339 // Method order is not significant. 340 // Ignore m.Pkg(). 341 m := t.Method(i) 342 hash += 3*hashString(m.Name()) + 5*h.Hash(m.Type()) 343 } 344 345 // Hash type restrictions. 346 terms, err := typeparams.InterfaceTermSet(t) 347 // if err != nil t has invalid type restrictions. 348 if err == nil { 349 hash += h.hashTermSet(terms) 350 } 351 352 return hash 353 354 case *types.Map: 355 return 9109 + 2*h.Hash(t.Key()) + 3*h.Hash(t.Elem()) 356 357 case *types.Chan: 358 return 9127 + 2*uint32(t.Dir()) + 3*h.Hash(t.Elem()) 359 360 case *types.Named: 361 hash := h.hashPtr(t.Obj()) 362 targs := typeparams.NamedTypeArgs(t) 363 for i := 0; i < targs.Len(); i++ { 364 targ := targs.At(i) 365 hash += 2 * h.Hash(targ) 366 } 367 return hash 368 369 case *typeparams.TypeParam: 370 return h.hashTypeParam(t) 371 372 case *types.Tuple: 373 return h.hashTuple(t) 374 } 375 376 panic(fmt.Sprintf("%T: %v", t, t)) 377 } 378 379 func (h Hasher) hashTuple(tuple *types.Tuple) uint32 { 380 // See go/types.identicalTypes for rationale. 381 n := tuple.Len() 382 var hash uint32 = 9137 + 2*uint32(n) 383 for i := 0; i < n; i++ { 384 hash += 3 * h.Hash(tuple.At(i).Type()) 385 } 386 return hash 387 } 388 389 func (h Hasher) hashUnion(t *typeparams.Union) uint32 { 390 // Hash type restrictions. 391 terms, err := typeparams.UnionTermSet(t) 392 // if err != nil t has invalid type restrictions. Fall back on a non-zero 393 // hash. 394 if err != nil { 395 return 9151 396 } 397 return h.hashTermSet(terms) 398 } 399 400 func (h Hasher) hashTermSet(terms []*typeparams.Term) uint32 { 401 var hash uint32 = 9157 + 2*uint32(len(terms)) 402 for _, term := range terms { 403 // term order is not significant. 404 termHash := h.Hash(term.Type()) 405 if term.Tilde() { 406 termHash *= 9161 407 } 408 hash += 3 * termHash 409 } 410 return hash 411 } 412 413 // hashTypeParam returns a hash of the type parameter t, with a hash value 414 // depending on whether t is contained in h.sigTParams. 415 // 416 // If h.sigTParams is set and contains t, then we are in the process of hashing 417 // a signature, and the hash value of t must depend only on t's index and 418 // constraint: signatures are considered identical modulo type parameter 419 // renaming. 420 // 421 // Otherwise the hash of t depends only on t's pointer identity. 422 func (h Hasher) hashTypeParam(t *typeparams.TypeParam) uint32 { 423 if h.sigTParams != nil { 424 i := t.Index() 425 if i >= 0 && i < h.sigTParams.Len() && t == h.sigTParams.At(i) { 426 return 9173 + 2*h.Hash(t.Constraint()) + 3*uint32(i) 427 } 428 } 429 return h.hashPtr(t.Obj()) 430 } 431 432 // hashPtr hashes the pointer identity of ptr. It uses h.ptrMap to ensure that 433 // pointers values are not dependent on the GC. 434 func (h Hasher) hashPtr(ptr interface{}) uint32 { 435 if hash, ok := h.ptrMap[ptr]; ok { 436 return hash 437 } 438 hash := uint32(reflect.ValueOf(ptr).Pointer()) 439 h.ptrMap[ptr] = hash 440 return hash 441 }