// MethodSet returns the method set of type T. It is thread-safe. // // If cache is nil, this function is equivalent to types.NewMethodSet(T). // Utility functions can thus expose an optional *MethodSetCache // parameter to clients that care about performance. // func (cache *MethodSetCache) MethodSet(T types.Type) *types.MethodSet { if cache == nil { return types.NewMethodSet(T) } cache.mu.Lock() defer cache.mu.Unlock() switch T := T.(type) { case *types.Named: return cache.lookupNamed(T).value case *types.Pointer: if N, ok := T.Elem().(*types.Named); ok { return cache.lookupNamed(N).pointer } } // all other types // (The map uses pointer equivalence, not type identity.) mset := cache.others[T] if mset == nil { mset = types.NewMethodSet(T) if cache.others == nil { cache.others = make(map[types.Type]*types.MethodSet) } cache.others[T] = mset } return mset }
// 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 } return hash + 3*h.hashTuple(t.Params()) + 5*h.hashTuple(t.Results()) case *types.Interface: var hash uint32 = 9103 for i, n := 0, t.NumMethods(); i < n; i++ { // See go/types.identicalMethods for rationale. // Method order is not significant. // Ignore m.Pkg(). m := t.Method(i) hash += 3*hashString(m.Name()) + 5*h.Hash(m.Type()) } 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: // Not safe with a copying GC; objects may move. return uint32(reflect.ValueOf(t.Obj()).Pointer()) case *types.Tuple: return h.hashTuple(t) } panic(t) }