github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/go/ssa/util.go (about) 1 // Copyright 2013 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 ssa 6 7 // This file defines a number of miscellaneous utility functions. 8 9 import ( 10 "fmt" 11 "go/ast" 12 "go/token" 13 "go/types" 14 "io" 15 "os" 16 "sync" 17 18 "github.com/powerman/golang-tools/go/ast/astutil" 19 "github.com/powerman/golang-tools/go/types/typeutil" 20 "github.com/powerman/golang-tools/internal/typeparams" 21 ) 22 23 //// Sanity checking utilities 24 25 // assert panics with the mesage msg if p is false. 26 // Avoid combining with expensive string formatting. 27 func assert(p bool, msg string) { 28 if !p { 29 panic(msg) 30 } 31 } 32 33 //// AST utilities 34 35 func unparen(e ast.Expr) ast.Expr { return astutil.Unparen(e) } 36 37 // isBlankIdent returns true iff e is an Ident with name "_". 38 // They have no associated types.Object, and thus no type. 39 // 40 func isBlankIdent(e ast.Expr) bool { 41 id, ok := e.(*ast.Ident) 42 return ok && id.Name == "_" 43 } 44 45 //// Type utilities. Some of these belong in go/types. 46 47 // isPointer returns true for types whose underlying type is a pointer. 48 func isPointer(typ types.Type) bool { 49 _, ok := typ.Underlying().(*types.Pointer) 50 return ok 51 } 52 53 func isInterface(T types.Type) bool { return types.IsInterface(T) } 54 55 // deref returns a pointer's element type; otherwise it returns typ. 56 func deref(typ types.Type) types.Type { 57 if p, ok := typ.Underlying().(*types.Pointer); ok { 58 return p.Elem() 59 } 60 return typ 61 } 62 63 // recvType returns the receiver type of method obj. 64 func recvType(obj *types.Func) types.Type { 65 return obj.Type().(*types.Signature).Recv().Type() 66 } 67 68 // isUntyped returns true for types that are untyped. 69 func isUntyped(typ types.Type) bool { 70 b, ok := typ.(*types.Basic) 71 return ok && b.Info()&types.IsUntyped != 0 72 } 73 74 // logStack prints the formatted "start" message to stderr and 75 // returns a closure that prints the corresponding "end" message. 76 // Call using 'defer logStack(...)()' to show builder stack on panic. 77 // Don't forget trailing parens! 78 // 79 func logStack(format string, args ...interface{}) func() { 80 msg := fmt.Sprintf(format, args...) 81 io.WriteString(os.Stderr, msg) 82 io.WriteString(os.Stderr, "\n") 83 return func() { 84 io.WriteString(os.Stderr, msg) 85 io.WriteString(os.Stderr, " end\n") 86 } 87 } 88 89 // newVar creates a 'var' for use in a types.Tuple. 90 func newVar(name string, typ types.Type) *types.Var { 91 return types.NewParam(token.NoPos, nil, name, typ) 92 } 93 94 // anonVar creates an anonymous 'var' for use in a types.Tuple. 95 func anonVar(typ types.Type) *types.Var { 96 return newVar("", typ) 97 } 98 99 var lenResults = types.NewTuple(anonVar(tInt)) 100 101 // makeLen returns the len builtin specialized to type func(T)int. 102 func makeLen(T types.Type) *Builtin { 103 lenParams := types.NewTuple(anonVar(T)) 104 return &Builtin{ 105 name: "len", 106 sig: types.NewSignature(nil, lenParams, lenResults, false), 107 } 108 } 109 110 // nonbasicTypes returns a list containing all of the types T in ts that are non-basic. 111 func nonbasicTypes(ts []types.Type) []types.Type { 112 if len(ts) == 0 { 113 return nil 114 } 115 added := make(map[types.Type]bool) // additionally filter duplicates 116 var filtered []types.Type 117 for _, T := range ts { 118 if _, basic := T.(*types.Basic); !basic { 119 if !added[T] { 120 added[T] = true 121 filtered = append(filtered, T) 122 } 123 } 124 } 125 return filtered 126 } 127 128 // isGeneric returns true if a package-level member is generic. 129 func isGeneric(m Member) bool { 130 switch m := m.(type) { 131 case *NamedConst, *Global: 132 return false 133 case *Type: 134 // lifted from types.isGeneric. 135 named, _ := m.Type().(*types.Named) 136 return named != nil && named.Obj() != nil && typeparams.NamedTypeArgs(named) == nil && typeparams.ForNamed(named) != nil 137 case *Function: 138 return len(m._TypeParams) != len(m._TypeArgs) 139 default: 140 panic("unreachable") 141 } 142 } 143 144 // receiverTypeArgs returns the type arguments to a function's reciever. 145 // Returns an empty list if obj does not have a reciever or its reciever does not have type arguments. 146 func receiverTypeArgs(obj *types.Func) []types.Type { 147 rtype := recvType(obj) 148 if rtype == nil { 149 return nil 150 } 151 if isPointer(rtype) { 152 rtype = rtype.(*types.Pointer).Elem() 153 } 154 named, ok := rtype.(*types.Named) 155 if !ok { 156 return nil 157 } 158 ts := typeparams.NamedTypeArgs(named) 159 if ts.Len() == 0 { 160 return nil 161 } 162 targs := make([]types.Type, ts.Len()) 163 for i := 0; i < ts.Len(); i++ { 164 targs[i] = ts.At(i) 165 } 166 return targs 167 } 168 169 // Mapping of a type T to a canonical instance C s.t. types.Indentical(T, C). 170 // Thread-safe. 171 type canonizer struct { 172 mu sync.Mutex 173 types typeutil.Map // map from type to a canonical instance 174 lists typeListMap // map from a list of types to a canonical instance 175 } 176 177 func newCanonizer() *canonizer { 178 c := &canonizer{} 179 h := typeutil.MakeHasher() 180 c.types.SetHasher(h) 181 c.lists.hasher = h 182 return c 183 } 184 185 // List returns a canonical representative of a list of types. 186 // Representative of the empty list is nil. 187 func (c *canonizer) List(ts []types.Type) *typeList { 188 if len(ts) == 0 { 189 return nil 190 } 191 192 c.mu.Lock() 193 defer c.mu.Unlock() 194 return c.lists.rep(ts) 195 } 196 197 // Type returns a canonical representative of type T. 198 func (c *canonizer) Type(T types.Type) types.Type { 199 c.mu.Lock() 200 defer c.mu.Unlock() 201 202 if r := c.types.At(T); r != nil { 203 return r.(types.Type) 204 } 205 c.types.Set(T, T) 206 return T 207 } 208 209 // A type for representating an canonized list of types. 210 type typeList []types.Type 211 212 func (l *typeList) identical(ts []types.Type) bool { 213 if l == nil { 214 return len(ts) == 0 215 } 216 n := len(*l) 217 if len(ts) != n { 218 return false 219 } 220 for i, left := range *l { 221 right := ts[i] 222 if !types.Identical(left, right) { 223 return false 224 } 225 } 226 return true 227 } 228 229 type typeListMap struct { 230 hasher typeutil.Hasher 231 buckets map[uint32][]*typeList 232 } 233 234 // rep returns a canonical representative of a slice of types. 235 func (m *typeListMap) rep(ts []types.Type) *typeList { 236 if m == nil || len(ts) == 0 { 237 return nil 238 } 239 240 if m.buckets == nil { 241 m.buckets = make(map[uint32][]*typeList) 242 } 243 244 h := m.hash(ts) 245 bucket := m.buckets[h] 246 for _, l := range bucket { 247 if l.identical(ts) { 248 return l 249 } 250 } 251 252 // not present. create a representative. 253 cp := make(typeList, len(ts)) 254 copy(cp, ts) 255 rep := &cp 256 257 m.buckets[h] = append(bucket, rep) 258 return rep 259 } 260 261 func (m *typeListMap) hash(ts []types.Type) uint32 { 262 if m == nil { 263 return 0 264 } 265 // Some smallish prime far away from typeutil.Hash. 266 n := len(ts) 267 h := uint32(13619) + 2*uint32(n) 268 for i := 0; i < n; i++ { 269 h += 3 * m.hasher.Hash(ts[i]) 270 } 271 return h 272 }