| // Copyright 2014 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| // Package typeutil defines various utilities for types, such as Map, | |
| // a mapping from types.Type to interface{} values. | |
| package typeutil // import "golang.org/x/tools/go/types/typeutil" | |
| import ( | |
| "bytes" | |
| "fmt" | |
| "go/types" | |
| "reflect" | |
| "golang.org/x/tools/internal/typeparams" | |
| ) | |
| // Map is a hash-table-based mapping from types (types.Type) to | |
| // arbitrary interface{} values. The concrete types that implement | |
| // the Type interface are pointers. Since they are not canonicalized, | |
| // == cannot be used to check for equivalence, and thus we cannot | |
| // simply use a Go map. | |
| // | |
| // Just as with map[K]V, a nil *Map is a valid empty map. | |
| // | |
| // Not thread-safe. | |
| type Map struct { | |
| hasher Hasher // shared by many Maps | |
| table map[uint32][]entry // maps hash to bucket; entry.key==nil means unused | |
| length int // number of map entries | |
| } | |
| // entry is an entry (key/value association) in a hash bucket. | |
| type entry struct { | |
| key types.Type | |
| value interface{} | |
| } | |
| // SetHasher sets the hasher used by Map. | |
| // | |
| // All Hashers are functionally equivalent but contain internal state | |
| // used to cache the results of hashing previously seen types. | |
| // | |
| // A single Hasher created by MakeHasher() may be shared among many | |
| // Maps. This is recommended if the instances have many keys in | |
| // common, as it will amortize the cost of hash computation. | |
| // | |
| // A Hasher may grow without bound as new types are seen. Even when a | |
| // type is deleted from the map, the Hasher never shrinks, since other | |
| // types in the map may reference the deleted type indirectly. | |
| // | |
| // Hashers are not thread-safe, and read-only operations such as | |
| // Map.Lookup require updates to the hasher, so a full Mutex lock (not a | |
| // read-lock) is require around all Map operations if a shared | |
| // hasher is accessed from multiple threads. | |
| // | |
| // If SetHasher is not called, the Map will create a private hasher at | |
| // the first call to Insert. | |
| func (m *Map) SetHasher(hasher Hasher) { | |
| m.hasher = hasher | |
| } | |
| // Delete removes the entry with the given key, if any. | |
| // It returns true if the entry was found. | |
| func (m *Map) Delete(key types.Type) bool { | |
| if m != nil && m.table != nil { | |
| hash := m.hasher.Hash(key) | |
| bucket := m.table[hash] | |
| for i, e := range bucket { | |
| if e.key != nil && types.Identical(key, e.key) { | |
| // We can't compact the bucket as it | |
| // would disturb iterators. | |
| bucket[i] = entry{} | |
| m.length-- | |
| return true | |
| } | |
| } | |
| } | |
| return false | |
| } | |
| // At returns the map entry for the given key. | |
| // The result is nil if the entry is not present. | |
| func (m *Map) At(key types.Type) interface{} { | |
| if m != nil && m.table != nil { | |
| for _, e := range m.table[m.hasher.Hash(key)] { | |
| if e.key != nil && types.Identical(key, e.key) { | |
| return e.value | |
| } | |
| } | |
| } | |
| return nil | |
| } | |
| // Set sets the map entry for key to val, | |
| // and returns the previous entry, if any. | |
| func (m *Map) Set(key types.Type, value interface{}) (prev interface{}) { | |
| if m.table != nil { | |
| hash := m.hasher.Hash(key) | |
| bucket := m.table[hash] | |
| var hole *entry | |
| for i, e := range bucket { | |
| if e.key == nil { | |
| hole = &bucket[i] | |
| } else if types.Identical(key, e.key) { | |
| prev = e.value | |
| bucket[i].value = value | |
| return | |
| } | |
| } | |
| if hole != nil { | |
| *hole = entry{key, value} // overwrite deleted entry | |
| } else { | |
| m.table[hash] = append(bucket, entry{key, value}) | |
| } | |
| } else { | |
| if m.hasher.memo == nil { | |
| m.hasher = MakeHasher() | |
| } | |
| hash := m.hasher.Hash(key) | |
| m.table = map[uint32][]entry{hash: {entry{key, value}}} | |
| } | |
| m.length++ | |
| return | |
| } | |
| // Len returns the number of map entries. | |
| func (m *Map) Len() int { | |
| if m != nil { | |
| return m.length | |
| } | |
| return 0 | |
| } | |
| // Iterate calls function f on each entry in the map in unspecified order. | |
| // | |
| // If f should mutate the map, Iterate provides the same guarantees as | |
| // Go maps: if f deletes a map entry that Iterate has not yet reached, | |
| // f will not be invoked for it, but if f inserts a map entry that | |
| // Iterate has not yet reached, whether or not f will be invoked for | |
| // it is unspecified. | |
| func (m *Map) Iterate(f func(key types.Type, value interface{})) { | |
| if m != nil { | |
| for _, bucket := range m.table { | |
| for _, e := range bucket { | |
| if e.key != nil { | |
| f(e.key, e.value) | |
| } | |
| } | |
| } | |
| } | |
| } | |
| // Keys returns a new slice containing the set of map keys. | |
| // The order is unspecified. | |
| func (m *Map) Keys() []types.Type { | |
| keys := make([]types.Type, 0, m.Len()) | |
| m.Iterate(func(key types.Type, _ interface{}) { | |
| keys = append(keys, key) | |
| }) | |
| return keys | |
| } | |
| func (m *Map) toString(values bool) string { | |
| if m == nil { | |
| return "{}" | |
| } | |
| var buf bytes.Buffer | |
| fmt.Fprint(&buf, "{") | |
| sep := "" | |
| m.Iterate(func(key types.Type, value interface{}) { | |
| fmt.Fprint(&buf, sep) | |
| sep = ", " | |
| fmt.Fprint(&buf, key) | |
| if values { | |
| fmt.Fprintf(&buf, ": %q", value) | |
| } | |
| }) | |
| fmt.Fprint(&buf, "}") | |
| return buf.String() | |
| } | |
| // String returns a string representation of the map's entries. | |
| // Values are printed using fmt.Sprintf("%v", v). | |
| // Order is unspecified. | |
| func (m *Map) String() string { | |
| return m.toString(true) | |
| } | |
| // KeysString returns a string representation of the map's key set. | |
| // Order is unspecified. | |
| func (m *Map) KeysString() string { | |
| return m.toString(false) | |
| } | |
| //////////////////////////////////////////////////////////////////////// | |
| // Hasher | |
| // A Hasher maps each type to its hash value. | |
| // For efficiency, a hasher uses memoization; thus its memory | |
| // footprint grows monotonically over time. | |
| // Hashers are not thread-safe. | |
| // Hashers have reference semantics. | |
| // Call MakeHasher to create a Hasher. | |
| type Hasher struct { | |
| memo map[types.Type]uint32 | |
| // ptrMap records pointer identity. | |
| ptrMap map[interface{}]uint32 | |
| // sigTParams holds type parameters from the signature being hashed. | |
| // Signatures are considered identical modulo renaming of type parameters, so | |
| // within the scope of a signature type the identity of the signature's type | |
| // parameters is just their index. | |
| // | |
| // Since the language does not currently support referring to uninstantiated | |
| // generic types or functions, and instantiated signatures do not have type | |
| // parameter lists, we should never encounter a second non-empty type | |
| // parameter list when hashing a generic signature. | |
| sigTParams *typeparams.TypeParamList | |
| } | |
| // MakeHasher returns a new Hasher instance. | |
| func MakeHasher() Hasher { | |
| return Hasher{ | |
| memo: make(map[types.Type]uint32), | |
| ptrMap: make(map[interface{}]uint32), | |
| sigTParams: nil, | |
| } | |
| } | |
| // Hash computes a hash value for the given type t such that | |
| // Identical(t, t') => Hash(t) == Hash(t'). | |
| func (h Hasher) Hash(t types.Type) uint32 { | |
| hash, ok := h.memo[t] | |
| if !ok { | |
| hash = h.hashFor(t) | |
| h.memo[t] = hash | |
| } | |
| return hash | |
| } | |
| // hashString computes the Fowler–Noll–Vo hash of s. | |
| func hashString(s string) uint32 { | |
| var h uint32 | |
| for i := 0; i < len(s); i++ { | |
| h ^= uint32(s[i]) | |
| h *= 16777619 | |
| } | |
| return h | |
| } | |
| // hashFor computes the hash of t. | |
| func (h Hasher) hashFor(t types.Type) uint32 { | |
| // See Identical for rationale. | |
| switch t := t.(type) { | |
| case *types.Basic: | |
| return uint32(t.Kind()) | |
| case *types.Array: | |
| return 9043 + 2*uint32(t.Len()) + 3*h.Hash(t.Elem()) | |
| case *types.Slice: | |
| return 9049 + 2*h.Hash(t.Elem()) | |
| case *types.Struct: | |
| var hash uint32 = 9059 | |
| for i, n := 0, t.NumFields(); i < n; i++ { | |
| f := t.Field(i) | |
| if f.Anonymous() { | |
| hash += 8861 | |
| } | |
| hash += hashString(t.Tag(i)) | |
| hash += hashString(f.Name()) // (ignore f.Pkg) | |
| hash += h.Hash(f.Type()) | |
| } | |
| return hash | |
| case *types.Pointer: | |
| return 9067 + 2*h.Hash(t.Elem()) | |
| case *types.Signature: | |
| var hash uint32 = 9091 | |
| if t.Variadic() { | |
| hash *= 8863 | |
| } | |
| // Use a separate hasher for types inside of the signature, where type | |
| // parameter identity is modified to be (index, constraint). We must use a | |
| // new memo for this hasher as type identity may be affected by this | |
| // masking. For example, in func[T any](*T), the identity of *T depends on | |
| // whether we are mapping the argument in isolation, or recursively as part | |
| // of hashing the signature. | |
| // | |
| // We should never encounter a generic signature while hashing another | |
| // generic signature, but defensively set sigTParams only if h.mask is | |
| // unset. | |
| tparams := typeparams.ForSignature(t) | |
| if h.sigTParams == nil && tparams.Len() != 0 { | |
| h = Hasher{ | |
| // There may be something more efficient than discarding the existing | |
| // memo, but it would require detecting whether types are 'tainted' by | |
| // references to type parameters. | |
| memo: make(map[types.Type]uint32), | |
| // Re-using ptrMap ensures that pointer identity is preserved in this | |
| // hasher. | |
| ptrMap: h.ptrMap, | |
| sigTParams: tparams, | |
| } | |
| } | |
| for i := 0; i < tparams.Len(); i++ { | |
| tparam := tparams.At(i) | |
| hash += 7 * h.Hash(tparam.Constraint()) | |
| } | |
| return hash + 3*h.hashTuple(t.Params()) + 5*h.hashTuple(t.Results()) | |
| case *typeparams.Union: | |
| return h.hashUnion(t) | |
| case *types.Interface: | |
| // Interfaces are identical if they have the same set of methods, with | |
| // identical names and types, and they have the same set of type | |
| // restrictions. See go/types.identical for more details. | |
| var hash uint32 = 9103 | |
| // Hash methods. | |
| for i, n := 0, t.NumMethods(); i < n; i++ { | |
| // Method order is not significant. | |
| // Ignore m.Pkg(). | |
| m := t.Method(i) | |
| // Use shallow hash on method signature to | |
| // avoid anonymous interface cycles. | |
| hash += 3*hashString(m.Name()) + 5*h.shallowHash(m.Type()) | |
| } | |
| // Hash type restrictions. | |
| terms, err := typeparams.InterfaceTermSet(t) | |
| // if err != nil t has invalid type restrictions. | |
| if err == nil { | |
| hash += h.hashTermSet(terms) | |
| } | |
| return hash | |
| case *types.Map: | |
| return 9109 + 2*h.Hash(t.Key()) + 3*h.Hash(t.Elem()) | |
| case *types.Chan: | |
| return 9127 + 2*uint32(t.Dir()) + 3*h.Hash(t.Elem()) | |
| case *types.Named: | |
| hash := h.hashPtr(t.Obj()) | |
| targs := typeparams.NamedTypeArgs(t) | |
| for i := 0; i < targs.Len(); i++ { | |
| targ := targs.At(i) | |
| hash += 2 * h.Hash(targ) | |
| } | |
| return hash | |
| case *typeparams.TypeParam: | |
| return h.hashTypeParam(t) | |
| case *types.Tuple: | |
| return h.hashTuple(t) | |
| } | |
| panic(fmt.Sprintf("%T: %v", t, t)) | |
| } | |
| func (h Hasher) hashTuple(tuple *types.Tuple) uint32 { | |
| // See go/types.identicalTypes for rationale. | |
| n := tuple.Len() | |
| hash := 9137 + 2*uint32(n) | |
| for i := 0; i < n; i++ { | |
| hash += 3 * h.Hash(tuple.At(i).Type()) | |
| } | |
| return hash | |
| } | |
| func (h Hasher) hashUnion(t *typeparams.Union) uint32 { | |
| // Hash type restrictions. | |
| terms, err := typeparams.UnionTermSet(t) | |
| // if err != nil t has invalid type restrictions. Fall back on a non-zero | |
| // hash. | |
| if err != nil { | |
| return 9151 | |
| } | |
| return h.hashTermSet(terms) | |
| } | |
| func (h Hasher) hashTermSet(terms []*typeparams.Term) uint32 { | |
| hash := 9157 + 2*uint32(len(terms)) | |
| for _, term := range terms { | |
| // term order is not significant. | |
| termHash := h.Hash(term.Type()) | |
| if term.Tilde() { | |
| termHash *= 9161 | |
| } | |
| hash += 3 * termHash | |
| } | |
| return hash | |
| } | |
| // hashTypeParam returns a hash of the type parameter t, with a hash value | |
| // depending on whether t is contained in h.sigTParams. | |
| // | |
| // If h.sigTParams is set and contains t, then we are in the process of hashing | |
| // a signature, and the hash value of t must depend only on t's index and | |
| // constraint: signatures are considered identical modulo type parameter | |
| // renaming. To avoid infinite recursion, we only hash the type parameter | |
| // index, and rely on types.Identical to handle signatures where constraints | |
| // are not identical. | |
| // | |
| // Otherwise the hash of t depends only on t's pointer identity. | |
| func (h Hasher) hashTypeParam(t *typeparams.TypeParam) uint32 { | |
| if h.sigTParams != nil { | |
| i := t.Index() | |
| if i >= 0 && i < h.sigTParams.Len() && t == h.sigTParams.At(i) { | |
| return 9173 + 3*uint32(i) | |
| } | |
| } | |
| return h.hashPtr(t.Obj()) | |
| } | |
| // hashPtr hashes the pointer identity of ptr. It uses h.ptrMap to ensure that | |
| // pointers values are not dependent on the GC. | |
| func (h Hasher) hashPtr(ptr interface{}) uint32 { | |
| if hash, ok := h.ptrMap[ptr]; ok { | |
| return hash | |
| } | |
| hash := uint32(reflect.ValueOf(ptr).Pointer()) | |
| h.ptrMap[ptr] = hash | |
| return hash | |
| } | |
| // shallowHash computes a hash of t without looking at any of its | |
| // element Types, to avoid potential anonymous cycles in the types of | |
| // interface methods. | |
| // | |
| // When an unnamed non-empty interface type appears anywhere among the | |
| // arguments or results of an interface method, there is a potential | |
| // for endless recursion. Consider: | |
| // | |
| // type X interface { m() []*interface { X } } | |
| // | |
| // The problem is that the Methods of the interface in m's result type | |
| // include m itself; there is no mention of the named type X that | |
| // might help us break the cycle. | |
| // (See comment in go/types.identical, case *Interface, for more.) | |
| func (h Hasher) shallowHash(t types.Type) uint32 { | |
| // t is the type of an interface method (Signature), | |
| // its params or results (Tuples), or their immediate | |
| // elements (mostly Slice, Pointer, Basic, Named), | |
| // so there's no need to optimize anything else. | |
| switch t := t.(type) { | |
| case *types.Signature: | |
| var hash uint32 = 604171 | |
| if t.Variadic() { | |
| hash *= 971767 | |
| } | |
| // The Signature/Tuple recursion is always finite | |
| // and invariably shallow. | |
| return hash + 1062599*h.shallowHash(t.Params()) + 1282529*h.shallowHash(t.Results()) | |
| case *types.Tuple: | |
| n := t.Len() | |
| hash := 9137 + 2*uint32(n) | |
| for i := 0; i < n; i++ { | |
| hash += 53471161 * h.shallowHash(t.At(i).Type()) | |
| } | |
| return hash | |
| case *types.Basic: | |
| return 45212177 * uint32(t.Kind()) | |
| case *types.Array: | |
| return 1524181 + 2*uint32(t.Len()) | |
| case *types.Slice: | |
| return 2690201 | |
| case *types.Struct: | |
| return 3326489 | |
| case *types.Pointer: | |
| return 4393139 | |
| case *typeparams.Union: | |
| return 562448657 | |
| case *types.Interface: | |
| return 2124679 // no recursion here | |
| case *types.Map: | |
| return 9109 | |
| case *types.Chan: | |
| return 9127 | |
| case *types.Named: | |
| return h.hashPtr(t.Obj()) | |
| case *typeparams.TypeParam: | |
| return h.hashPtr(t.Obj()) | |
| } | |
| panic(fmt.Sprintf("shallowHash: %T: %v", t, t)) | |
| } |