Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201028153306-37f0764111ff / go / ssa / methods.go
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 utilities for population of method sets.
8
9 import (
10         "fmt"
11         "go/types"
12 )
13
14 // MethodValue returns the Function implementing method sel, building
15 // wrapper methods on demand.  It returns nil if sel denotes an
16 // abstract (interface) method.
17 //
18 // Precondition: sel.Kind() == MethodVal.
19 //
20 // Thread-safe.
21 //
22 // EXCLUSIVE_LOCKS_ACQUIRED(prog.methodsMu)
23 //
24 func (prog *Program) MethodValue(sel *types.Selection) *Function {
25         if sel.Kind() != types.MethodVal {
26                 panic(fmt.Sprintf("MethodValue(%s) kind != MethodVal", sel))
27         }
28         T := sel.Recv()
29         if isInterface(T) {
30                 return nil // abstract method
31         }
32         if prog.mode&LogSource != 0 {
33                 defer logStack("MethodValue %s %v", T, sel)()
34         }
35
36         prog.methodsMu.Lock()
37         defer prog.methodsMu.Unlock()
38
39         return prog.addMethod(prog.createMethodSet(T), sel)
40 }
41
42 // LookupMethod returns the implementation of the method of type T
43 // identified by (pkg, name).  It returns nil if the method exists but
44 // is abstract, and panics if T has no such method.
45 //
46 func (prog *Program) LookupMethod(T types.Type, pkg *types.Package, name string) *Function {
47         sel := prog.MethodSets.MethodSet(T).Lookup(pkg, name)
48         if sel == nil {
49                 panic(fmt.Sprintf("%s has no method %s", T, types.Id(pkg, name)))
50         }
51         return prog.MethodValue(sel)
52 }
53
54 // methodSet contains the (concrete) methods of a non-interface type.
55 type methodSet struct {
56         mapping  map[string]*Function // populated lazily
57         complete bool                 // mapping contains all methods
58 }
59
60 // Precondition: !isInterface(T).
61 // EXCLUSIVE_LOCKS_REQUIRED(prog.methodsMu)
62 func (prog *Program) createMethodSet(T types.Type) *methodSet {
63         mset, ok := prog.methodSets.At(T).(*methodSet)
64         if !ok {
65                 mset = &methodSet{mapping: make(map[string]*Function)}
66                 prog.methodSets.Set(T, mset)
67         }
68         return mset
69 }
70
71 // EXCLUSIVE_LOCKS_REQUIRED(prog.methodsMu)
72 func (prog *Program) addMethod(mset *methodSet, sel *types.Selection) *Function {
73         if sel.Kind() == types.MethodExpr {
74                 panic(sel)
75         }
76         id := sel.Obj().Id()
77         fn := mset.mapping[id]
78         if fn == nil {
79                 obj := sel.Obj().(*types.Func)
80
81                 needsPromotion := len(sel.Index()) > 1
82                 needsIndirection := !isPointer(recvType(obj)) && isPointer(sel.Recv())
83                 if needsPromotion || needsIndirection {
84                         fn = makeWrapper(prog, sel)
85                 } else {
86                         fn = prog.declaredFunc(obj)
87                 }
88                 if fn.Signature.Recv() == nil {
89                         panic(fn) // missing receiver
90                 }
91                 mset.mapping[id] = fn
92         }
93         return fn
94 }
95
96 // RuntimeTypes returns a new unordered slice containing all
97 // concrete types in the program for which a complete (non-empty)
98 // method set is required at run-time.
99 //
100 // Thread-safe.
101 //
102 // EXCLUSIVE_LOCKS_ACQUIRED(prog.methodsMu)
103 //
104 func (prog *Program) RuntimeTypes() []types.Type {
105         prog.methodsMu.Lock()
106         defer prog.methodsMu.Unlock()
107
108         var res []types.Type
109         prog.methodSets.Iterate(func(T types.Type, v interface{}) {
110                 if v.(*methodSet).complete {
111                         res = append(res, T)
112                 }
113         })
114         return res
115 }
116
117 // declaredFunc returns the concrete function/method denoted by obj.
118 // Panic ensues if there is none.
119 //
120 func (prog *Program) declaredFunc(obj *types.Func) *Function {
121         if v := prog.packageLevelValue(obj); v != nil {
122                 return v.(*Function)
123         }
124         panic("no concrete method: " + obj.String())
125 }
126
127 // needMethodsOf ensures that runtime type information (including the
128 // complete method set) is available for the specified type T and all
129 // its subcomponents.
130 //
131 // needMethodsOf must be called for at least every type that is an
132 // operand of some MakeInterface instruction, and for the type of
133 // every exported package member.
134 //
135 // Precondition: T is not a method signature (*Signature with Recv()!=nil).
136 //
137 // Thread-safe.  (Called via emitConv from multiple builder goroutines.)
138 //
139 // TODO(adonovan): make this faster.  It accounts for 20% of SSA build time.
140 //
141 // EXCLUSIVE_LOCKS_ACQUIRED(prog.methodsMu)
142 //
143 func (prog *Program) needMethodsOf(T types.Type) {
144         prog.methodsMu.Lock()
145         prog.needMethods(T, false)
146         prog.methodsMu.Unlock()
147 }
148
149 // Precondition: T is not a method signature (*Signature with Recv()!=nil).
150 // Recursive case: skip => don't create methods for T.
151 //
152 // EXCLUSIVE_LOCKS_REQUIRED(prog.methodsMu)
153 //
154 func (prog *Program) needMethods(T types.Type, skip bool) {
155         // Each package maintains its own set of types it has visited.
156         if prevSkip, ok := prog.runtimeTypes.At(T).(bool); ok {
157                 // needMethods(T) was previously called
158                 if !prevSkip || skip {
159                         return // already seen, with same or false 'skip' value
160                 }
161         }
162         prog.runtimeTypes.Set(T, skip)
163
164         tmset := prog.MethodSets.MethodSet(T)
165
166         if !skip && !isInterface(T) && tmset.Len() > 0 {
167                 // Create methods of T.
168                 mset := prog.createMethodSet(T)
169                 if !mset.complete {
170                         mset.complete = true
171                         n := tmset.Len()
172                         for i := 0; i < n; i++ {
173                                 prog.addMethod(mset, tmset.At(i))
174                         }
175                 }
176         }
177
178         // Recursion over signatures of each method.
179         for i := 0; i < tmset.Len(); i++ {
180                 sig := tmset.At(i).Type().(*types.Signature)
181                 prog.needMethods(sig.Params(), false)
182                 prog.needMethods(sig.Results(), false)
183         }
184
185         switch t := T.(type) {
186         case *types.Basic:
187                 // nop
188
189         case *types.Interface:
190                 // nop---handled by recursion over method set.
191
192         case *types.Pointer:
193                 prog.needMethods(t.Elem(), false)
194
195         case *types.Slice:
196                 prog.needMethods(t.Elem(), false)
197
198         case *types.Chan:
199                 prog.needMethods(t.Elem(), false)
200
201         case *types.Map:
202                 prog.needMethods(t.Key(), false)
203                 prog.needMethods(t.Elem(), false)
204
205         case *types.Signature:
206                 if t.Recv() != nil {
207                         panic(fmt.Sprintf("Signature %s has Recv %s", t, t.Recv()))
208                 }
209                 prog.needMethods(t.Params(), false)
210                 prog.needMethods(t.Results(), false)
211
212         case *types.Named:
213                 // A pointer-to-named type can be derived from a named
214                 // type via reflection.  It may have methods too.
215                 prog.needMethods(types.NewPointer(T), false)
216
217                 // Consider 'type T struct{S}' where S has methods.
218                 // Reflection provides no way to get from T to struct{S},
219                 // only to S, so the method set of struct{S} is unwanted,
220                 // so set 'skip' flag during recursion.
221                 prog.needMethods(t.Underlying(), true)
222
223         case *types.Array:
224                 prog.needMethods(t.Elem(), false)
225
226         case *types.Struct:
227                 for i, n := 0, t.NumFields(); i < n; i++ {
228                         prog.needMethods(t.Field(i).Type(), false)
229                 }
230
231         case *types.Tuple:
232                 for i, n := 0, t.Len(); i < n; i++ {
233                         prog.needMethods(t.At(i).Type(), false)
234                 }
235
236         default:
237                 panic(T)
238         }
239 }