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