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