1
2
3
4
5 package ssa
6
7
8
9 import (
10 "fmt"
11 "go/ast"
12 "go/token"
13 "go/types"
14 "io"
15 "os"
16 "sync"
17
18 "golang.org/x/tools/go/ast/astutil"
19 "golang.org/x/tools/go/types/typeutil"
20 "golang.org/x/tools/internal/aliases"
21 "golang.org/x/tools/internal/typeparams"
22 "golang.org/x/tools/internal/typesinternal"
23 )
24
25
26
27
28
29 func assert(p bool, msg string) {
30 if !p {
31 panic(msg)
32 }
33 }
34
35
36
37 func unparen(e ast.Expr) ast.Expr { return astutil.Unparen(e) }
38
39
40
41 func isBlankIdent(e ast.Expr) bool {
42 id, ok := e.(*ast.Ident)
43 return ok && id.Name == "_"
44 }
45
46
47
48
49 func isNonTypeParamInterface(t types.Type) bool {
50 return !typeparams.IsTypeParam(t) && types.IsInterface(t)
51 }
52
53
54
55 func isBasic(t types.Type) bool {
56 _, ok := t.(*types.Basic)
57 return ok
58 }
59
60
61
62 func isString(t types.Type) bool {
63 basic, ok := t.(*types.Basic)
64 return ok && basic.Info()&types.IsString != 0
65 }
66
67
68
69 func isByteSlice(t types.Type) bool {
70 if b, ok := t.(*types.Slice); ok {
71 e, _ := b.Elem().Underlying().(*types.Basic)
72 return e != nil && e.Kind() == types.Byte
73 }
74 return false
75 }
76
77
78
79 func isRuneSlice(t types.Type) bool {
80 if b, ok := t.(*types.Slice); ok {
81 e, _ := b.Elem().Underlying().(*types.Basic)
82 return e != nil && e.Kind() == types.Rune
83 }
84 return false
85 }
86
87
88
89
90
91
92 func isBasicConvTypes(tset termList) bool {
93 basics := 0
94 all := underIs(tset, func(t types.Type) bool {
95 if isBasic(t) {
96 basics++
97 return true
98 }
99 return isByteSlice(t) || isRuneSlice(t)
100 })
101 return all && basics >= 1 && tset.Len()-basics <= 1
102 }
103
104
105 func isPointer(t types.Type) bool {
106 return is[*types.Pointer](t.Underlying())
107 }
108
109
110
111
112
113 func isPointerCore(t types.Type) bool {
114 return is[*types.Pointer](typeparams.CoreType(t))
115 }
116
117 func is[T any](x any) bool {
118 _, ok := x.(T)
119 return ok
120 }
121
122
123 func recvType(obj *types.Func) types.Type {
124 return obj.Type().(*types.Signature).Recv().Type()
125 }
126
127
128
129 func fieldOf(typ types.Type, index int) *types.Var {
130 if st, ok := typeparams.CoreType(typ).(*types.Struct); ok {
131 if 0 <= index && index < st.NumFields() {
132 return st.Field(index)
133 }
134 }
135 return nil
136 }
137
138
139 func isUntyped(typ types.Type) bool {
140
141 b, ok := typ.(*types.Basic)
142 return ok && b.Info()&types.IsUntyped != 0
143 }
144
145
146
147
148
149 func logStack(format string, args ...interface{}) func() {
150 msg := fmt.Sprintf(format, args...)
151 io.WriteString(os.Stderr, msg)
152 io.WriteString(os.Stderr, "\n")
153 return func() {
154 io.WriteString(os.Stderr, msg)
155 io.WriteString(os.Stderr, " end\n")
156 }
157 }
158
159
160 func newVar(name string, typ types.Type) *types.Var {
161 return types.NewParam(token.NoPos, nil, name, typ)
162 }
163
164
165 func anonVar(typ types.Type) *types.Var {
166 return newVar("", typ)
167 }
168
169 var lenResults = types.NewTuple(anonVar(tInt))
170
171
172 func makeLen(T types.Type) *Builtin {
173 lenParams := types.NewTuple(anonVar(T))
174 return &Builtin{
175 name: "len",
176 sig: types.NewSignature(nil, lenParams, lenResults, false),
177 }
178 }
179
180
181
182 func receiverTypeArgs(method *types.Func) []types.Type {
183 recv := method.Type().(*types.Signature).Recv()
184 _, named := typesinternal.ReceiverNamed(recv)
185 if named == nil {
186 return nil
187 }
188 ts := named.TypeArgs()
189 if ts.Len() == 0 {
190 return nil
191 }
192 targs := make([]types.Type, ts.Len())
193 for i := 0; i < ts.Len(); i++ {
194 targs[i] = ts.At(i)
195 }
196 return targs
197 }
198
199
200
201 func recvAsFirstArg(sig *types.Signature) *types.Signature {
202 params := make([]*types.Var, 0, 1+sig.Params().Len())
203 params = append(params, sig.Recv())
204 for i := 0; i < sig.Params().Len(); i++ {
205 params = append(params, sig.Params().At(i))
206 }
207 return types.NewSignatureType(nil, nil, nil, types.NewTuple(params...), sig.Results(), sig.Variadic())
208 }
209
210
211
212 func instance(info *types.Info, expr ast.Expr) bool {
213
214
215 var id *ast.Ident
216 switch x := expr.(type) {
217 case *ast.Ident:
218 id = x
219 case *ast.SelectorExpr:
220 id = x.Sel
221 default:
222 return false
223 }
224 _, ok := info.Instances[id]
225 return ok
226 }
227
228
229 func instanceArgs(info *types.Info, id *ast.Ident) []types.Type {
230 targList := info.Instances[id].TypeArgs
231 if targList == nil {
232 return nil
233 }
234
235 targs := make([]types.Type, targList.Len())
236 for i, n := 0, targList.Len(); i < n; i++ {
237 targs[i] = targList.At(i)
238 }
239 return targs
240 }
241
242
243
244 type canonizer struct {
245 mu sync.Mutex
246 types typeutil.Map
247 lists typeListMap
248 }
249
250 func newCanonizer() *canonizer {
251 c := &canonizer{}
252 h := typeutil.MakeHasher()
253 c.types.SetHasher(h)
254 c.lists.hasher = h
255 return c
256 }
257
258
259
260 func (c *canonizer) List(ts []types.Type) *typeList {
261 if len(ts) == 0 {
262 return nil
263 }
264
265 unaliasAll := func(ts []types.Type) []types.Type {
266
267 var found bool
268 for _, t := range ts {
269 if _, ok := t.(*aliases.Alias); ok {
270 found = true
271 break
272 }
273 }
274 if !found {
275 return ts
276 }
277
278 cp := make([]types.Type, len(ts))
279 for i, t := range ts {
280 cp[i] = aliases.Unalias(t)
281 }
282 return cp
283 }
284 l := unaliasAll(ts)
285
286 c.mu.Lock()
287 defer c.mu.Unlock()
288 return c.lists.rep(l)
289 }
290
291
292
293
294
295
296 func (c *canonizer) Type(T types.Type) types.Type {
297 T = aliases.Unalias(T)
298
299 c.mu.Lock()
300 defer c.mu.Unlock()
301
302 if r := c.types.At(T); r != nil {
303 return r.(types.Type)
304 }
305 c.types.Set(T, T)
306 return T
307 }
308
309
310 type typeList []types.Type
311
312 func (l *typeList) identical(ts []types.Type) bool {
313 if l == nil {
314 return len(ts) == 0
315 }
316 n := len(*l)
317 if len(ts) != n {
318 return false
319 }
320 for i, left := range *l {
321 right := ts[i]
322 if !types.Identical(left, right) {
323 return false
324 }
325 }
326 return true
327 }
328
329 type typeListMap struct {
330 hasher typeutil.Hasher
331 buckets map[uint32][]*typeList
332 }
333
334
335 func (m *typeListMap) rep(ts []types.Type) *typeList {
336 if m == nil || len(ts) == 0 {
337 return nil
338 }
339
340 if m.buckets == nil {
341 m.buckets = make(map[uint32][]*typeList)
342 }
343
344 h := m.hash(ts)
345 bucket := m.buckets[h]
346 for _, l := range bucket {
347 if l.identical(ts) {
348 return l
349 }
350 }
351
352
353 cp := make(typeList, len(ts))
354 copy(cp, ts)
355 rep := &cp
356
357 m.buckets[h] = append(bucket, rep)
358 return rep
359 }
360
361 func (m *typeListMap) hash(ts []types.Type) uint32 {
362 if m == nil {
363 return 0
364 }
365
366 n := len(ts)
367 h := uint32(13619) + 2*uint32(n)
368 for i := 0; i < n; i++ {
369 h += 3 * m.hasher.Hash(ts[i])
370 }
371 return h
372 }
373
374
375 func (canon *canonizer) instantiateMethod(m *types.Func, targs []types.Type, ctxt *types.Context) *types.Func {
376 recv := recvType(m)
377 if p, ok := aliases.Unalias(recv).(*types.Pointer); ok {
378 recv = p.Elem()
379 }
380 named := aliases.Unalias(recv).(*types.Named)
381 inst, err := types.Instantiate(ctxt, named.Origin(), targs, false)
382 if err != nil {
383 panic(err)
384 }
385 rep := canon.Type(inst)
386 obj, _, _ := types.LookupFieldOrMethod(rep, true, m.Pkg(), m.Name())
387 return obj.(*types.Func)
388 }
389
390
391 func isSyntactic(pkg *Package) bool { return pkg.syntax }
392
393
394 func mapValues[K comparable, V any](m map[K]V) []V {
395 vals := make([]V, 0, len(m))
396 for _, fn := range m {
397 vals = append(vals, fn)
398 }
399 return vals
400
401 }
402
View as plain text