Source file
src/go/types/methodset.go
1
2
3
4
5
6
7 package types
8
9 import (
10 "fmt"
11 "sort"
12 "strings"
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 strings.Builder
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
68
69
70
71
72 func NewMethodSet(T Type) *MethodSet {
73
74
75
76
77
78
79
80
81
82
83 if t := asNamed(T); t != nil && isPointer(t) {
84 return &emptyMethodSet
85 }
86
87
88 var base methodSet
89
90 typ, isPtr := deref(T)
91
92
93 if isPtr && IsInterface(typ) {
94 return &emptyMethodSet
95 }
96
97
98 current := []embeddedType{{typ, nil, isPtr, false}}
99
100
101
102
103
104
105 var seen instanceLookup
106
107
108 for len(current) > 0 {
109 var next []embeddedType
110
111
112 var fset map[string]bool
113 var mset methodSet
114
115 for _, e := range current {
116 typ := e.typ
117
118
119
120 if named := asNamed(typ); named != nil {
121 if alt := seen.lookup(named); alt != nil {
122
123
124
125
126
127 continue
128 }
129 seen.add(named)
130
131 for i := 0; i < named.NumMethods(); i++ {
132 mset = mset.addOne(named.Method(i), concat(e.index, i), e.indirect, e.multiples)
133 }
134 }
135
136 switch t := under(typ).(type) {
137 case *Struct:
138 for i, f := range t.fields {
139 if fset == nil {
140 fset = make(map[string]bool)
141 }
142 fset[f.Id()] = true
143
144
145
146
147
148 if f.embedded {
149 typ, isPtr := deref(f.typ)
150
151
152
153 next = append(next, embeddedType{typ, concat(e.index, i), e.indirect || isPtr, e.multiples})
154 }
155 }
156
157 case *Interface:
158 mset = mset.add(t.typeSet().methods, e.index, true, e.multiples)
159 }
160 }
161
162
163
164 for k, m := range mset {
165 if _, found := base[k]; !found {
166
167 if fset[k] {
168 m = nil
169 }
170 if base == nil {
171 base = make(methodSet)
172 }
173 base[k] = m
174 }
175 }
176
177
178
179 for k := range fset {
180 if _, found := base[k]; !found {
181 if base == nil {
182 base = make(methodSet)
183 }
184 base[k] = nil
185 }
186 }
187
188 current = consolidateMultiples(next)
189 }
190
191 if len(base) == 0 {
192 return &emptyMethodSet
193 }
194
195
196 var list []*Selection
197 for _, m := range base {
198 if m != nil {
199 m.recv = T
200 list = append(list, m)
201 }
202 }
203
204 sort.Slice(list, func(i, j int) bool {
205 return list[i].obj.Id() < list[j].obj.Id()
206 })
207 return &MethodSet{list}
208 }
209
210
211
212
213 type methodSet map[string]*Selection
214
215
216
217
218 func (s methodSet) add(list []*Func, index []int, indirect bool, multiples bool) methodSet {
219 if len(list) == 0 {
220 return s
221 }
222 for i, f := range list {
223 s = s.addOne(f, concat(index, i), indirect, multiples)
224 }
225 return s
226 }
227
228 func (s methodSet) addOne(f *Func, index []int, indirect bool, multiples bool) methodSet {
229 if s == nil {
230 s = make(methodSet)
231 }
232 key := f.Id()
233
234 if !multiples {
235
236
237
238
239 if _, found := s[key]; !found && (indirect || !f.hasPtrRecv()) {
240 s[key] = &Selection{MethodVal, nil, f, index, indirect}
241 return s
242 }
243 }
244 s[key] = nil
245 return s
246 }
247
View as plain text