golang.org/x/tools@v0.21.0/go/types/typeutil/methodsetcache.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 // This file implements a cache of method sets. 6 7 package typeutil 8 9 import ( 10 "go/types" 11 "sync" 12 13 "golang.org/x/tools/internal/aliases" 14 ) 15 16 // A MethodSetCache records the method set of each type T for which 17 // MethodSet(T) is called so that repeat queries are fast. 18 // The zero value is a ready-to-use cache instance. 19 type MethodSetCache struct { 20 mu sync.Mutex 21 named map[*types.Named]struct{ value, pointer *types.MethodSet } // method sets for named N and *N 22 others map[types.Type]*types.MethodSet // all other types 23 } 24 25 // MethodSet returns the method set of type T. It is thread-safe. 26 // 27 // If cache is nil, this function is equivalent to types.NewMethodSet(T). 28 // Utility functions can thus expose an optional *MethodSetCache 29 // parameter to clients that care about performance. 30 func (cache *MethodSetCache) MethodSet(T types.Type) *types.MethodSet { 31 if cache == nil { 32 return types.NewMethodSet(T) 33 } 34 cache.mu.Lock() 35 defer cache.mu.Unlock() 36 37 switch T := aliases.Unalias(T).(type) { 38 case *types.Named: 39 return cache.lookupNamed(T).value 40 41 case *types.Pointer: 42 if N, ok := aliases.Unalias(T.Elem()).(*types.Named); ok { 43 return cache.lookupNamed(N).pointer 44 } 45 } 46 47 // all other types 48 // (The map uses pointer equivalence, not type identity.) 49 mset := cache.others[T] 50 if mset == nil { 51 mset = types.NewMethodSet(T) 52 if cache.others == nil { 53 cache.others = make(map[types.Type]*types.MethodSet) 54 } 55 cache.others[T] = mset 56 } 57 return mset 58 } 59 60 func (cache *MethodSetCache) lookupNamed(named *types.Named) struct{ value, pointer *types.MethodSet } { 61 if cache.named == nil { 62 cache.named = make(map[*types.Named]struct{ value, pointer *types.MethodSet }) 63 } 64 // Avoid recomputing mset(*T) for each distinct Pointer 65 // instance whose underlying type is a named type. 66 msets, ok := cache.named[named] 67 if !ok { 68 msets.value = types.NewMethodSet(named) 69 msets.pointer = types.NewMethodSet(types.NewPointer(named)) 70 cache.named[named] = msets 71 } 72 return msets 73 }