1 | // Copyright 2022 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 | import ( |
8 | "go/types" |
9 | |
10 | "golang.org/x/tools/internal/typeparams" |
11 | ) |
12 | |
13 | // tpWalker walks over types looking for parameterized types. |
14 | // |
15 | // NOTE: Adapted from go/types/infer.go. If that is exported in a future release remove this copy. |
16 | type tpWalker struct { |
17 | seen map[types.Type]bool |
18 | } |
19 | |
20 | // isParameterized returns true when typ contains any type parameters. |
21 | func (w *tpWalker) isParameterized(typ types.Type) (res bool) { |
22 | // NOTE: Adapted from go/types/infer.go. Try to keep in sync. |
23 | |
24 | // detect cycles |
25 | if x, ok := w.seen[typ]; ok { |
26 | return x |
27 | } |
28 | w.seen[typ] = false |
29 | defer func() { |
30 | w.seen[typ] = res |
31 | }() |
32 | |
33 | switch t := typ.(type) { |
34 | case nil, *types.Basic: // TODO(gri) should nil be handled here? |
35 | break |
36 | |
37 | case *types.Array: |
38 | return w.isParameterized(t.Elem()) |
39 | |
40 | case *types.Slice: |
41 | return w.isParameterized(t.Elem()) |
42 | |
43 | case *types.Struct: |
44 | for i, n := 0, t.NumFields(); i < n; i++ { |
45 | if w.isParameterized(t.Field(i).Type()) { |
46 | return true |
47 | } |
48 | } |
49 | |
50 | case *types.Pointer: |
51 | return w.isParameterized(t.Elem()) |
52 | |
53 | case *types.Tuple: |
54 | n := t.Len() |
55 | for i := 0; i < n; i++ { |
56 | if w.isParameterized(t.At(i).Type()) { |
57 | return true |
58 | } |
59 | } |
60 | |
61 | case *types.Signature: |
62 | // t.tparams may not be nil if we are looking at a signature |
63 | // of a generic function type (or an interface method) that is |
64 | // part of the type we're testing. We don't care about these type |
65 | // parameters. |
66 | // Similarly, the receiver of a method may declare (rather then |
67 | // use) type parameters, we don't care about those either. |
68 | // Thus, we only need to look at the input and result parameters. |
69 | return w.isParameterized(t.Params()) || w.isParameterized(t.Results()) |
70 | |
71 | case *types.Interface: |
72 | for i, n := 0, t.NumMethods(); i < n; i++ { |
73 | if w.isParameterized(t.Method(i).Type()) { |
74 | return true |
75 | } |
76 | } |
77 | terms, err := typeparams.InterfaceTermSet(t) |
78 | if err != nil { |
79 | panic(err) |
80 | } |
81 | for _, term := range terms { |
82 | if w.isParameterized(term.Type()) { |
83 | return true |
84 | } |
85 | } |
86 | |
87 | case *types.Map: |
88 | return w.isParameterized(t.Key()) || w.isParameterized(t.Elem()) |
89 | |
90 | case *types.Chan: |
91 | return w.isParameterized(t.Elem()) |
92 | |
93 | case *types.Named: |
94 | args := typeparams.NamedTypeArgs(t) |
95 | // TODO(taking): this does not match go/types/infer.go. Check with rfindley. |
96 | if params := typeparams.ForNamed(t); params.Len() > args.Len() { |
97 | return true |
98 | } |
99 | for i, n := 0, args.Len(); i < n; i++ { |
100 | if w.isParameterized(args.At(i)) { |
101 | return true |
102 | } |
103 | } |
104 | |
105 | case *typeparams.TypeParam: |
106 | return true |
107 | |
108 | default: |
109 | panic(t) // unreachable |
110 | } |
111 | |
112 | return false |
113 | } |
114 | |
115 | func (w *tpWalker) anyParameterized(ts []types.Type) bool { |
116 | for _, t := range ts { |
117 | if w.isParameterized(t) { |
118 | return true |
119 | } |
120 | } |
121 | return false |
122 | } |
123 |
Members