GoPLS Viewer

Home|gopls/go/types/typeutil/map.go
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.
7package typeutil // import "golang.org/x/tools/go/types/typeutil"
8
9import (
10    "bytes"
11    "fmt"
12    "go/types"
13    "reflect"
14
15    "golang.org/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.
27type Map struct {
28    hasher Hasher             // shared by many Maps
29    table  map[uint32][]entry // maps hash to bucket; entry.key==nil means unused
30    length int                // number of map entries
31}
32
33// entry is an entry (key/value association) in a hash bucket.
34type entry struct {
35    key   types.Type
36    value interface{}
37}
38
39// SetHasher sets the hasher used by Map.
40//
41// All Hashers are functionally equivalent but contain internal state
42// used to cache the results of hashing previously seen types.
43//
44// A single Hasher created by MakeHasher() may be shared among many
45// Maps.  This is recommended if the instances have many keys in
46// common, as it will amortize the cost of hash computation.
47//
48// A Hasher may grow without bound as new types are seen.  Even when a
49// type is deleted from the map, the Hasher never shrinks, since other
50// types in the map may reference the deleted type indirectly.
51//
52// Hashers are not thread-safe, and read-only operations such as
53// Map.Lookup require updates to the hasher, so a full Mutex lock (not a
54// read-lock) is require around all Map operations if a shared
55// hasher is accessed from multiple threads.
56//
57// If SetHasher is not called, the Map will create a private hasher at
58// the first call to Insert.
59func (m *MapSetHasher(hasher Hasher) {
60    m.hasher = hasher
61}
62
63// Delete removes the entry with the given key, if any.
64// It returns true if the entry was found.
65func (m *MapDelete(key types.Typebool {
66    if m != nil && m.table != nil {
67        hash := m.hasher.Hash(key)
68        bucket := m.table[hash]
69        for ie := range bucket {
70            if e.key != nil && types.Identical(keye.key) {
71                // We can't compact the bucket as it
72                // would disturb iterators.
73                bucket[i] = entry{}
74                m.length--
75                return true
76            }
77        }
78    }
79    return false
80}
81
82// At returns the map entry for the given key.
83// The result is nil if the entry is not present.
84func (m *MapAt(key types.Type) interface{} {
85    if m != nil && m.table != nil {
86        for _e := range m.table[m.hasher.Hash(key)] {
87            if e.key != nil && types.Identical(keye.key) {
88                return e.value
89            }
90        }
91    }
92    return nil
93}
94
95// Set sets the map entry for key to val,
96// and returns the previous entry, if any.
97func (m *MapSet(key types.Typevalue interface{}) (prev interface{}) {
98    if m.table != nil {
99        hash := m.hasher.Hash(key)
100        bucket := m.table[hash]
101        var hole *entry
102        for ie := range bucket {
103            if e.key == nil {
104                hole = &bucket[i]
105            } else if types.Identical(keye.key) {
106                prev = e.value
107                bucket[i].value = value
108                return
109            }
110        }
111
112        if hole != nil {
113            *hole = entry{keyvalue// overwrite deleted entry
114        } else {
115            m.table[hash] = append(bucketentry{keyvalue})
116        }
117    } else {
118        if m.hasher.memo == nil {
119            m.hasher = MakeHasher()
120        }
121        hash := m.hasher.Hash(key)
122        m.table = map[uint32][]entry{hash: {entry{keyvalue}}}
123    }
124
125    m.length++
126    return
127}
128
129// Len returns the number of map entries.
130func (m *MapLen() int {
131    if m != nil {
132        return m.length
133    }
134    return 0
135}
136
137// Iterate calls function f on each entry in the map in unspecified order.
138//
139// If f should mutate the map, Iterate provides the same guarantees as
140// Go maps: if f deletes a map entry that Iterate has not yet reached,
141// f will not be invoked for it, but if f inserts a map entry that
142// Iterate has not yet reached, whether or not f will be invoked for
143// it is unspecified.
144func (m *MapIterate(f func(key types.Typevalue interface{})) {
145    if m != nil {
146        for _bucket := range m.table {
147            for _e := range bucket {
148                if e.key != nil {
149                    f(e.keye.value)
150                }
151            }
152        }
153    }
154}
155
156// Keys returns a new slice containing the set of map keys.
157// The order is unspecified.
158func (m *MapKeys() []types.Type {
159    keys := make([]types.Type0m.Len())
160    m.Iterate(func(key types.Type_ interface{}) {
161        keys = append(keyskey)
162    })
163    return keys
164}
165
166func (m *MaptoString(values boolstring {
167    if m == nil {
168        return "{}"
169    }
170    var buf bytes.Buffer
171    fmt.Fprint(&buf"{")
172    sep := ""
173    m.Iterate(func(key types.Typevalue interface{}) {
174        fmt.Fprint(&bufsep)
175        sep = ", "
176        fmt.Fprint(&bufkey)
177        if values {
178            fmt.Fprintf(&buf": %q"value)
179        }
180    })
181    fmt.Fprint(&buf"}")
182    return buf.String()
183}
184
185// String returns a string representation of the map's entries.
186// Values are printed using fmt.Sprintf("%v", v).
187// Order is unspecified.
188func (m *MapString() string {
189    return m.toString(true)
190}
191
192// KeysString returns a string representation of the map's key set.
193// Order is unspecified.
194func (m *MapKeysString() string {
195    return m.toString(false)
196}
197
198////////////////////////////////////////////////////////////////////////
199// Hasher
200
201// A Hasher maps each type to its hash value.
202// For efficiency, a hasher uses memoization; thus its memory
203// footprint grows monotonically over time.
204// Hashers are not thread-safe.
205// Hashers have reference semantics.
206// Call MakeHasher to create a Hasher.
207type Hasher struct {
208    memo map[types.Type]uint32
209
210    // ptrMap records pointer identity.
211    ptrMap map[interface{}]uint32
212
213    // sigTParams holds type parameters from the signature being hashed.
214    // Signatures are considered identical modulo renaming of type parameters, so
215    // within the scope of a signature type the identity of the signature's type
216    // parameters is just their index.
217    //
218    // Since the language does not currently support referring to uninstantiated
219    // generic types or functions, and instantiated signatures do not have type
220    // parameter lists, we should never encounter a second non-empty type
221    // parameter list when hashing a generic signature.
222    sigTParams *typeparams.TypeParamList
223}
224
225// MakeHasher returns a new Hasher instance.
226func MakeHasher() Hasher {
227    return Hasher{
228        memo:       make(map[types.Type]uint32),
229        ptrMap:     make(map[interface{}]uint32),
230        sigTParamsnil,
231    }
232}
233
234// Hash computes a hash value for the given type t such that
235// Identical(t, t') => Hash(t) == Hash(t').
236func (h HasherHash(t types.Typeuint32 {
237    hashok := h.memo[t]
238    if !ok {
239        hash = h.hashFor(t)
240        h.memo[t] = hash
241    }
242    return hash
243}
244
245// hashString computes the Fowler–Noll–Vo hash of s.
246func hashString(s stringuint32 {
247    var h uint32
248    for i := 0i < len(s); i++ {
249        h ^= uint32(s[i])
250        h *= 16777619
251    }
252    return h
253}
254
255// hashFor computes the hash of t.
256func (h HasherhashFor(t types.Typeuint32 {
257    // See Identical for rationale.
258    switch t := t.(type) {
259    case *types.Basic:
260        return uint32(t.Kind())
261
262    case *types.Array:
263        return 9043 + 2*uint32(t.Len()) + 3*h.Hash(t.Elem())
264
265    case *types.Slice:
266        return 9049 + 2*h.Hash(t.Elem())
267
268    case *types.Struct:
269        var hash uint32 = 9059
270        for in := 0t.NumFields(); i < ni++ {
271            f := t.Field(i)
272            if f.Anonymous() {
273                hash += 8861
274            }
275            hash += hashString(t.Tag(i))
276            hash += hashString(f.Name()) // (ignore f.Pkg)
277            hash += h.Hash(f.Type())
278        }
279        return hash
280
281    case *types.Pointer:
282        return 9067 + 2*h.Hash(t.Elem())
283
284    case *types.Signature:
285        var hash uint32 = 9091
286        if t.Variadic() {
287            hash *= 8863
288        }
289
290        // Use a separate hasher for types inside of the signature, where type
291        // parameter identity is modified to be (index, constraint). We must use a
292        // new memo for this hasher as type identity may be affected by this
293        // masking. For example, in func[T any](*T), the identity of *T depends on
294        // whether we are mapping the argument in isolation, or recursively as part
295        // of hashing the signature.
296        //
297        // We should never encounter a generic signature while hashing another
298        // generic signature, but defensively set sigTParams only if h.mask is
299        // unset.
300        tparams := typeparams.ForSignature(t)
301        if h.sigTParams == nil && tparams.Len() != 0 {
302            h = Hasher{
303                // There may be something more efficient than discarding the existing
304                // memo, but it would require detecting whether types are 'tainted' by
305                // references to type parameters.
306                memomake(map[types.Type]uint32),
307                // Re-using ptrMap ensures that pointer identity is preserved in this
308                // hasher.
309                ptrMap:     h.ptrMap,
310                sigTParamstparams,
311            }
312        }
313
314        for i := 0i < tparams.Len(); i++ {
315            tparam := tparams.At(i)
316            hash += 7 * h.Hash(tparam.Constraint())
317        }
318
319        return hash + 3*h.hashTuple(t.Params()) + 5*h.hashTuple(t.Results())
320
321    case *typeparams.Union:
322        return h.hashUnion(t)
323
324    case *types.Interface:
325        // Interfaces are identical if they have the same set of methods, with
326        // identical names and types, and they have the same set of type
327        // restrictions. See go/types.identical for more details.
328        var hash uint32 = 9103
329
330        // Hash methods.
331        for in := 0t.NumMethods(); i < ni++ {
332            // Method order is not significant.
333            // Ignore m.Pkg().
334            m := t.Method(i)
335            // Use shallow hash on method signature to
336            // avoid anonymous interface cycles.
337            hash += 3*hashString(m.Name()) + 5*h.shallowHash(m.Type())
338        }
339
340        // Hash type restrictions.
341        termserr := typeparams.InterfaceTermSet(t)
342        // if err != nil t has invalid type restrictions.
343        if err == nil {
344            hash += h.hashTermSet(terms)
345        }
346
347        return hash
348
349    case *types.Map:
350        return 9109 + 2*h.Hash(t.Key()) + 3*h.Hash(t.Elem())
351
352    case *types.Chan:
353        return 9127 + 2*uint32(t.Dir()) + 3*h.Hash(t.Elem())
354
355    case *types.Named:
356        hash := h.hashPtr(t.Obj())
357        targs := typeparams.NamedTypeArgs(t)
358        for i := 0i < targs.Len(); i++ {
359            targ := targs.At(i)
360            hash += 2 * h.Hash(targ)
361        }
362        return hash
363
364    case *typeparams.TypeParam:
365        return h.hashTypeParam(t)
366
367    case *types.Tuple:
368        return h.hashTuple(t)
369    }
370
371    panic(fmt.Sprintf("%T: %v"tt))
372}
373
374func (h HasherhashTuple(tuple *types.Tupleuint32 {
375    // See go/types.identicalTypes for rationale.
376    n := tuple.Len()
377    hash := 9137 + 2*uint32(n)
378    for i := 0i < ni++ {
379        hash += 3 * h.Hash(tuple.At(i).Type())
380    }
381    return hash
382}
383
384func (h HasherhashUnion(t *typeparams.Unionuint32 {
385    // Hash type restrictions.
386    termserr := typeparams.UnionTermSet(t)
387    // if err != nil t has invalid type restrictions. Fall back on a non-zero
388    // hash.
389    if err != nil {
390        return 9151
391    }
392    return h.hashTermSet(terms)
393}
394
395func (h HasherhashTermSet(terms []*typeparams.Termuint32 {
396    hash := 9157 + 2*uint32(len(terms))
397    for _term := range terms {
398        // term order is not significant.
399        termHash := h.Hash(term.Type())
400        if term.Tilde() {
401            termHash *= 9161
402        }
403        hash += 3 * termHash
404    }
405    return hash
406}
407
408// hashTypeParam returns a hash of the type parameter t, with a hash value
409// depending on whether t is contained in h.sigTParams.
410//
411// If h.sigTParams is set and contains t, then we are in the process of hashing
412// a signature, and the hash value of t must depend only on t's index and
413// constraint: signatures are considered identical modulo type parameter
414// renaming. To avoid infinite recursion, we only hash the type parameter
415// index, and rely on types.Identical to handle signatures where constraints
416// are not identical.
417//
418// Otherwise the hash of t depends only on t's pointer identity.
419func (h HasherhashTypeParam(t *typeparams.TypeParamuint32 {
420    if h.sigTParams != nil {
421        i := t.Index()
422        if i >= 0 && i < h.sigTParams.Len() && t == h.sigTParams.At(i) {
423            return 9173 + 3*uint32(i)
424        }
425    }
426    return h.hashPtr(t.Obj())
427}
428
429// hashPtr hashes the pointer identity of ptr. It uses h.ptrMap to ensure that
430// pointers values are not dependent on the GC.
431func (h HasherhashPtr(ptr interface{}) uint32 {
432    if hashok := h.ptrMap[ptr]; ok {
433        return hash
434    }
435    hash := uint32(reflect.ValueOf(ptr).Pointer())
436    h.ptrMap[ptr] = hash
437    return hash
438}
439
440// shallowHash computes a hash of t without looking at any of its
441// element Types, to avoid potential anonymous cycles in the types of
442// interface methods.
443//
444// When an unnamed non-empty interface type appears anywhere among the
445// arguments or results of an interface method, there is a potential
446// for endless recursion. Consider:
447//
448//    type X interface { m() []*interface { X } }
449//
450// The problem is that the Methods of the interface in m's result type
451// include m itself; there is no mention of the named type X that
452// might help us break the cycle.
453// (See comment in go/types.identical, case *Interface, for more.)
454func (h HashershallowHash(t types.Typeuint32 {
455    // t is the type of an interface method (Signature),
456    // its params or results (Tuples), or their immediate
457    // elements (mostly Slice, Pointer, Basic, Named),
458    // so there's no need to optimize anything else.
459    switch t := t.(type) {
460    case *types.Signature:
461        var hash uint32 = 604171
462        if t.Variadic() {
463            hash *= 971767
464        }
465        // The Signature/Tuple recursion is always finite
466        // and invariably shallow.
467        return hash + 1062599*h.shallowHash(t.Params()) + 1282529*h.shallowHash(t.Results())
468
469    case *types.Tuple:
470        n := t.Len()
471        hash := 9137 + 2*uint32(n)
472        for i := 0i < ni++ {
473            hash += 53471161 * h.shallowHash(t.At(i).Type())
474        }
475        return hash
476
477    case *types.Basic:
478        return 45212177 * uint32(t.Kind())
479
480    case *types.Array:
481        return 1524181 + 2*uint32(t.Len())
482
483    case *types.Slice:
484        return 2690201
485
486    case *types.Struct:
487        return 3326489
488
489    case *types.Pointer:
490        return 4393139
491
492    case *typeparams.Union:
493        return 562448657
494
495    case *types.Interface:
496        return 2124679 // no recursion here
497
498    case *types.Map:
499        return 9109
500
501    case *types.Chan:
502        return 9127
503
504    case *types.Named:
505        return h.hashPtr(t.Obj())
506
507    case *typeparams.TypeParam:
508        return h.hashPtr(t.Obj())
509    }
510    panic(fmt.Sprintf("shallowHash: %T: %v"tt))
511}
512
MembersX
Map.At
Hasher.sigTParams
hashString.i
Hasher.hashUnion.t
Hasher.hashTypeParam.h
Map.At.m
Hasher.hashFor.t
Hasher.hashFor.BlockStmt.targs
Hasher.hashPtr
Map.Set
Hasher.hashFor
Hasher.hashFor.BlockStmt.hash
Hasher.hashTermSet.RangeStmt_10942.term
Hasher.hashTuple.tuple
hashString.h
Map.Delete.m
Map.Set.BlockStmt.hole
Map.Set.BlockStmt.RangeStmt_3193.e
Hasher.hashFor.BlockStmt.BlockStmt.tparam
Hasher.hashTuple.h
Hasher.shallowHash
Map.SetHasher
MakeHasher
bytes
Map.SetHasher.m
Map.String
Hasher.shallowHash.BlockStmt.i
reflect
entry
Hasher.Hash.t
Hasher.hashFor.h
Hasher.hashFor.BlockStmt.n
Map.hasher
Map.KeysString.m
Map.Delete.BlockStmt.RangeStmt_2377.e
Map.toString.sep
Hasher.hashPtr.hash
Map.length
Hasher.memo
Hasher.ptrMap
Map.toString.values
Map.Delete
Map.Set.prev
Map.Len
Hasher.hashTuple
Map
Hasher.Hash.h
Hasher.hashUnion
Map.table
hashString.s
Map.At.key
Map.Set.value
Map.Iterate.BlockStmt.RangeStmt_4279.bucket
Hasher.hashFor.BlockStmt.BlockStmt.targ
Hasher.hashTuple.i
Hasher.hashPtr.h
Hasher.shallowHash.BlockStmt.hash
Map.Delete.BlockStmt.RangeStmt_2377.i
Map.Iterate.m
Map.SetHasher.hasher
hashString
Hasher.hashTermSet.terms
entry.value
Map.Keys.keys
Hasher.hashTypeParam.t
Hasher.shallowHash.h
Map.Delete.key
Map.Set.key
Map.toString.buf
Hasher.hashFor.BlockStmt.i
Hasher.shallowHash.BlockStmt.n
Map.Keys.m
Map.String.m
Map.Len.m
Map.Iterate.f
Map.At.BlockStmt.RangeStmt_2792.e
Hasher.shallowHash.t
Hasher.hashTuple.n
Map.toString.m
Hasher.hashFor.BlockStmt.BlockStmt.m
Hasher.hashFor.BlockStmt.err
Hasher.hashUnion.err
Hasher.hashTypeParam
Hasher.hashPtr.ptr
Map.KeysString
Hasher.Hash
Hasher.hashTermSet
Map.Keys
Hasher.hashTermSet.h
Map.Delete.BlockStmt.hash
Hasher.hashFor.BlockStmt.tparams
Hasher.hashUnion.terms
Map.Iterate
Hasher.hashFor.BlockStmt.BlockStmt.f
Map.toString
Hasher.hashFor.BlockStmt.terms
Map.Set.m
Map.Iterate.BlockStmt.RangeStmt_4279.BlockStmt.RangeStmt_4315.e
Hasher.hashTermSet.RangeStmt_10942.BlockStmt.termHash
Hasher
Map.Set.BlockStmt.RangeStmt_3193.i
entry.key
Map.Set.BlockStmt.hash
Hasher.hashUnion.h
Hasher.hashTypeParam.BlockStmt.i
Members
X