Source file
src/go/types/methodset.go
1
2
3
4
5
6
7 package types
8
9 import (
10 "bytes"
11 "fmt"
12 "sort"
13 )
14
15
16
17
18 type MethodSet struct {
19 list []*Selection
20 }
21
22 func (s *MethodSet) String() string {
23 if s.Len() == 0 {
24 return "MethodSet {}"
25 }
26
27 var buf bytes.Buffer
28 fmt.Fprintln(&buf, "MethodSet {")
29 for _, f := range s.list {
30 fmt.Fprintf(&buf, "\t%s\n", f)
31 }
32 fmt.Fprintln(&buf, "}")
33 return buf.String()
34 }
35
36
37 func (s *MethodSet) Len() int { return len(s.list) }
38
39
40 func (s *MethodSet) At(i int) *Selection { return s.list[i] }
41
42
43 func (s *MethodSet) Lookup(pkg *Package, name string) *Selection {
44 if s.Len() == 0 {
45 return nil
46 }
47
48 key := Id(pkg, name)
49 i := sort.Search(len(s.list), func(i int) bool {
50 m := s.list[i]
51 return m.obj.Id() >= key
52 })
53 if i < len(s.list) {
54 m := s.list[i]
55 if m.obj.Id() == key {
56 return m
57 }
58 }
59 return nil
60 }
61
62
63 var emptyMethodSet MethodSet
64
65
66
67 func NewMethodSet(T Type) *MethodSet {
68
69
70
71
72 var base methodSet
73
74 typ, isPtr := deref(T)
75
76
77 if isPtr && IsInterface(typ) {
78 return &emptyMethodSet
79 }
80
81
82 current := []embeddedType{{typ, nil, isPtr, false}}
83
84
85
86
87
88
89
90
91 var seen map[*Named]bool
92
93
94 for len(current) > 0 {
95 var next []embeddedType
96
97
98 var fset fieldSet
99 var mset methodSet
100
101 for _, e := range current {
102 typ := e.typ
103
104
105
106 if named, _ := typ.(*Named); named != nil {
107 if seen[named] {
108
109
110
111
112
113 continue
114 }
115 if seen == nil {
116 seen = make(map[*Named]bool)
117 }
118 seen[named] = true
119
120 mset = mset.add(named.methods, e.index, e.indirect, e.multiples)
121
122
123 typ = named.underlying
124 }
125
126 switch t := typ.(type) {
127 case *Struct:
128 for i, f := range t.fields {
129 fset = fset.add(f, e.multiples)
130
131
132
133
134
135 if f.anonymous {
136 typ, isPtr := deref(f.typ)
137
138
139
140 next = append(next, embeddedType{typ, concat(e.index, i), e.indirect || isPtr, e.multiples})
141 }
142 }
143
144 case *Interface:
145 mset = mset.add(t.allMethods, e.index, true, e.multiples)
146 }
147 }
148
149
150
151 for k, m := range mset {
152 if _, found := base[k]; !found {
153
154 if _, found := fset[k]; found {
155 m = nil
156 }
157 if base == nil {
158 base = make(methodSet)
159 }
160 base[k] = m
161 }
162 }
163
164
165
166
167 for k, f := range fset {
168 if f == nil {
169 if _, found := base[k]; !found {
170 if base == nil {
171 base = make(methodSet)
172 }
173 base[k] = nil
174 }
175 }
176 }
177
178 current = consolidateMultiples(next)
179 }
180
181 if len(base) == 0 {
182 return &emptyMethodSet
183 }
184
185
186 var list []*Selection
187 for _, m := range base {
188 if m != nil {
189 m.recv = T
190 list = append(list, m)
191 }
192 }
193
194 sort.Slice(list, func(i, j int) bool {
195 return list[i].obj.Id() < list[j].obj.Id()
196 })
197 return &MethodSet{list}
198 }
199
200
201
202
203 type fieldSet map[string]*Var
204
205
206
207
208 func (s fieldSet) add(f *Var, multiples bool) fieldSet {
209 if s == nil {
210 s = make(fieldSet)
211 }
212 key := f.Id()
213
214 if !multiples {
215 if _, found := s[key]; !found {
216 s[key] = f
217 return s
218 }
219 }
220 s[key] = nil
221 return s
222 }
223
224
225
226
227 type methodSet map[string]*Selection
228
229
230
231
232 func (s methodSet) add(list []*Func, index []int, indirect bool, multiples bool) methodSet {
233 if len(list) == 0 {
234 return s
235 }
236 if s == nil {
237 s = make(methodSet)
238 }
239 for i, f := range list {
240 key := f.Id()
241
242 if !multiples {
243
244
245
246
247 if _, found := s[key]; !found && (indirect || !ptrRecv(f)) {
248 s[key] = &Selection{MethodVal, nil, f, concat(index, i), indirect}
249 continue
250 }
251 }
252 s[key] = nil
253 }
254 return s
255 }
256
257
258
259 func ptrRecv(f *Func) bool {
260 _, isPtr := deref(f.typ.(*Signature).recv.typ)
261 return isPtr
262 }
263
View as plain text