1
2
3
4
5 package ssa
6
7
8
9 import (
10 "fmt"
11 "go/types"
12
13 "golang.org/x/tools/internal/typeparams"
14 )
15
16
17
18
19
20
21
22
23
24
25 func (prog *Program) MethodValue(sel *types.Selection) *Function {
26 if sel.Kind() != types.MethodVal {
27 panic(fmt.Sprintf("MethodValue(%s) kind != MethodVal", sel))
28 }
29 T := sel.Recv()
30 if types.IsInterface(T) {
31 return nil
32 }
33 if prog.mode&LogSource != 0 {
34 defer logStack("MethodValue %s %v", T, sel)()
35 }
36
37 var m *Function
38 b := builder{created: &creator{}}
39
40 prog.methodsMu.Lock()
41
42
43 if !prog.parameterized.isParameterized(T) {
44 m = prog.addMethod(prog.createMethodSet(T), sel, b.created)
45 }
46 prog.methodsMu.Unlock()
47
48 if m == nil {
49 return nil
50 }
51 for !b.done() {
52 b.buildCreated()
53 b.needsRuntimeTypes()
54 }
55 return m
56 }
57
58
59
60
61 func (prog *Program) LookupMethod(T types.Type, pkg *types.Package, name string) *Function {
62 sel := prog.MethodSets.MethodSet(T).Lookup(pkg, name)
63 if sel == nil {
64 panic(fmt.Sprintf("%s has no method %s", T, types.Id(pkg, name)))
65 }
66 return prog.MethodValue(sel)
67 }
68
69
70 type methodSet struct {
71 mapping map[string]*Function
72 complete bool
73 }
74
75
76
77 func (prog *Program) createMethodSet(T types.Type) *methodSet {
78 if prog.mode&SanityCheckFunctions != 0 {
79 if types.IsInterface(T) || prog.parameterized.isParameterized(T) {
80 panic("type is interface or parameterized")
81 }
82 }
83 mset, ok := prog.methodSets.At(T).(*methodSet)
84 if !ok {
85 mset = &methodSet{mapping: make(map[string]*Function)}
86 prog.methodSets.Set(T, mset)
87 }
88 return mset
89 }
90
91
92
93
94 func (prog *Program) addMethod(mset *methodSet, sel *types.Selection, cr *creator) *Function {
95 if sel.Kind() == types.MethodExpr {
96 panic(sel)
97 }
98 id := sel.Obj().Id()
99 fn := mset.mapping[id]
100 if fn == nil {
101 sel := toSelection(sel)
102 obj := sel.obj.(*types.Func)
103
104 needsPromotion := len(sel.index) > 1
105 needsIndirection := !isPointer(recvType(obj)) && isPointer(sel.recv)
106 if needsPromotion || needsIndirection {
107 fn = makeWrapper(prog, sel, cr)
108 } else {
109 fn = prog.originFunc(obj)
110 if fn.typeparams.Len() > 0 {
111 targs := receiverTypeArgs(obj)
112 fn = prog.lookupOrCreateInstance(fn, targs, cr)
113 }
114 }
115 if fn.Signature.Recv() == nil {
116 panic(fn)
117 }
118 mset.mapping[id] = fn
119 }
120 return fn
121 }
122
123
124
125
126
127
128
129
130 func (prog *Program) RuntimeTypes() []types.Type {
131 prog.methodsMu.Lock()
132 defer prog.methodsMu.Unlock()
133
134 var res []types.Type
135 prog.methodSets.Iterate(func(T types.Type, v interface{}) {
136 if v.(*methodSet).complete {
137 res = append(res, T)
138 }
139 })
140 return res
141 }
142
143
144
145 func (prog *Program) declaredFunc(obj *types.Func) *Function {
146 if v := prog.packageLevelMember(obj); v != nil {
147 return v.(*Function)
148 }
149 panic("no concrete method: " + obj.String())
150 }
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170 func (prog *Program) needMethodsOf(T types.Type, cr *creator) {
171 prog.methodsMu.Lock()
172 prog.needMethods(T, false, cr)
173 prog.methodsMu.Unlock()
174 }
175
176
177
178
179
180
181 func (prog *Program) needMethods(T types.Type, skip bool, cr *creator) {
182
183 if prevSkip, ok := prog.runtimeTypes.At(T).(bool); ok {
184
185 if !prevSkip || skip {
186 return
187 }
188 }
189 prog.runtimeTypes.Set(T, skip)
190
191 tmset := prog.MethodSets.MethodSet(T)
192
193 if !skip && !types.IsInterface(T) && tmset.Len() > 0 {
194
195 mset := prog.createMethodSet(T)
196 if !mset.complete {
197 mset.complete = true
198 n := tmset.Len()
199 for i := 0; i < n; i++ {
200 prog.addMethod(mset, tmset.At(i), cr)
201 }
202 }
203 }
204
205
206 for i := 0; i < tmset.Len(); i++ {
207 sig := tmset.At(i).Type().(*types.Signature)
208 prog.needMethods(sig.Params(), false, cr)
209 prog.needMethods(sig.Results(), false, cr)
210 }
211
212 switch t := T.(type) {
213 case *types.Basic:
214
215
216 case *types.Interface:
217
218
219 case *types.Pointer:
220 prog.needMethods(t.Elem(), false, cr)
221
222 case *types.Slice:
223 prog.needMethods(t.Elem(), false, cr)
224
225 case *types.Chan:
226 prog.needMethods(t.Elem(), false, cr)
227
228 case *types.Map:
229 prog.needMethods(t.Key(), false, cr)
230 prog.needMethods(t.Elem(), false, cr)
231
232 case *types.Signature:
233 if t.Recv() != nil {
234 panic(fmt.Sprintf("Signature %s has Recv %s", t, t.Recv()))
235 }
236 prog.needMethods(t.Params(), false, cr)
237 prog.needMethods(t.Results(), false, cr)
238
239 case *types.Named:
240
241
242 prog.needMethods(types.NewPointer(T), false, cr)
243
244
245
246
247
248 prog.needMethods(t.Underlying(), true, cr)
249
250 case *types.Array:
251 prog.needMethods(t.Elem(), false, cr)
252
253 case *types.Struct:
254 for i, n := 0, t.NumFields(); i < n; i++ {
255 prog.needMethods(t.Field(i).Type(), false, cr)
256 }
257
258 case *types.Tuple:
259 for i, n := 0, t.Len(); i < n; i++ {
260 prog.needMethods(t.At(i).Type(), false, cr)
261 }
262
263 case *typeparams.TypeParam:
264 panic(T)
265
266 case *typeparams.Union:
267
268
269 default:
270 panic(T)
271 }
272 }
273
View as plain text