Source file
src/go/types/typeset.go
1
2
3
4
5 package types
6
7 import (
8 "go/token"
9 . "internal/types/errors"
10 "sort"
11 "strings"
12 )
13
14
15
16
17
18
19
20
21
22
23
24
25
26 type _TypeSet struct {
27 methods []*Func
28 terms termlist
29 comparable bool
30 }
31
32
33 func (s *_TypeSet) IsEmpty() bool { return s.terms.isEmpty() }
34
35
36 func (s *_TypeSet) IsAll() bool { return s.IsMethodSet() && len(s.methods) == 0 }
37
38
39 func (s *_TypeSet) IsMethodSet() bool { return !s.comparable && s.terms.isAll() }
40
41
42 func (s *_TypeSet) IsComparable(seen map[Type]bool) bool {
43 if s.terms.isAll() {
44 return s.comparable
45 }
46 return s.is(func(t *term) bool {
47 return t != nil && comparable(t.typ, false, seen, nil)
48 })
49 }
50
51
52 func (s *_TypeSet) NumMethods() int { return len(s.methods) }
53
54
55
56 func (s *_TypeSet) Method(i int) *Func { return s.methods[i] }
57
58
59 func (s *_TypeSet) LookupMethod(pkg *Package, name string, foldCase bool) (int, *Func) {
60 return lookupMethod(s.methods, pkg, name, foldCase)
61 }
62
63 func (s *_TypeSet) String() string {
64 switch {
65 case s.IsEmpty():
66 return "∅"
67 case s.IsAll():
68 return "𝓤"
69 }
70
71 hasMethods := len(s.methods) > 0
72 hasTerms := s.hasTerms()
73
74 var buf strings.Builder
75 buf.WriteByte('{')
76 if s.comparable {
77 buf.WriteString("comparable")
78 if hasMethods || hasTerms {
79 buf.WriteString("; ")
80 }
81 }
82 for i, m := range s.methods {
83 if i > 0 {
84 buf.WriteString("; ")
85 }
86 buf.WriteString(m.String())
87 }
88 if hasMethods && hasTerms {
89 buf.WriteString("; ")
90 }
91 if hasTerms {
92 buf.WriteString(s.terms.String())
93 }
94 buf.WriteString("}")
95 return buf.String()
96 }
97
98
99
100
101
102 func (s *_TypeSet) hasTerms() bool { return !s.terms.isEmpty() && !s.terms.isAll() }
103
104
105 func (s1 *_TypeSet) subsetOf(s2 *_TypeSet) bool { return s1.terms.subsetOf(s2.terms) }
106
107
108
109
110
111
112 func (s *_TypeSet) is(f func(*term) bool) bool {
113 if !s.hasTerms() {
114 return f(nil)
115 }
116 for _, t := range s.terms {
117 assert(t.typ != nil)
118 if !f(t) {
119 return false
120 }
121 }
122 return true
123 }
124
125
126
127
128 func (s *_TypeSet) underIs(f func(Type) bool) bool {
129 if !s.hasTerms() {
130 return f(nil)
131 }
132 for _, t := range s.terms {
133 assert(t.typ != nil)
134
135 u := t.typ
136 if !t.tilde {
137 u = under(u)
138 }
139 if debug {
140 assert(Identical(u, under(u)))
141 }
142 if !f(u) {
143 return false
144 }
145 }
146 return true
147 }
148
149
150 var topTypeSet = _TypeSet{terms: allTermlist}
151
152
153 func computeInterfaceTypeSet(check *Checker, pos token.Pos, ityp *Interface) *_TypeSet {
154 if ityp.tset != nil {
155 return ityp.tset
156 }
157
158
159
160
161
162
163
164
165
166
167
168 if !ityp.complete {
169 return &topTypeSet
170 }
171
172 if check != nil && check.conf._Trace {
173
174
175
176 if !pos.IsValid() && len(ityp.methods) > 0 {
177 pos = ityp.methods[0].pos
178 }
179
180 check.trace(pos, "-- type set for %s", ityp)
181 check.indent++
182 defer func() {
183 check.indent--
184 check.trace(pos, "=> %s ", ityp.typeSet())
185 }()
186 }
187
188
189
190
191
192
193 ityp.tset = &_TypeSet{terms: allTermlist}
194
195 var unionSets map[*Union]*_TypeSet
196 if check != nil {
197 if check.unionTypeSets == nil {
198 check.unionTypeSets = make(map[*Union]*_TypeSet)
199 }
200 unionSets = check.unionTypeSets
201 } else {
202 unionSets = make(map[*Union]*_TypeSet)
203 }
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218 var seen objset
219 var allMethods []*Func
220 mpos := make(map[*Func]token.Pos)
221 addMethod := func(pos token.Pos, m *Func, explicit bool) {
222 switch other := seen.insert(m); {
223 case other == nil:
224 allMethods = append(allMethods, m)
225 mpos[m] = pos
226 case explicit:
227 if check != nil {
228 check.errorf(atPos(pos), DuplicateDecl, "duplicate method %s", m.name)
229 check.errorf(atPos(mpos[other.(*Func)]), DuplicateDecl, "\tother declaration of %s", m.name)
230 }
231 default:
232
233
234
235
236
237 if check != nil {
238 check.later(func() {
239 if !check.allowVersion(m.pkg, atPos(pos), go1_14) || !Identical(m.typ, other.Type()) {
240 check.errorf(atPos(pos), DuplicateDecl, "duplicate method %s", m.name)
241 check.errorf(atPos(mpos[other.(*Func)]), DuplicateDecl, "\tother declaration of %s", m.name)
242 }
243 }).describef(atPos(pos), "duplicate method check for %s", m.name)
244 }
245 }
246 }
247
248 for _, m := range ityp.methods {
249 addMethod(m.pos, m, true)
250 }
251
252
253 allTerms := allTermlist
254 allComparable := false
255 for i, typ := range ityp.embeddeds {
256
257
258
259 var pos token.Pos
260 if ityp.embedPos != nil {
261 pos = (*ityp.embedPos)[i]
262 }
263 var comparable bool
264 var terms termlist
265 switch u := under(typ).(type) {
266 case *Interface:
267
268 assert(!isTypeParam(typ))
269 tset := computeInterfaceTypeSet(check, pos, u)
270
271 if check != nil && check.isImportedConstraint(typ) && !check.verifyVersionf(atPos(pos), go1_18, "embedding constraint interface %s", typ) {
272 continue
273 }
274 comparable = tset.comparable
275 for _, m := range tset.methods {
276 addMethod(pos, m, false)
277 }
278 terms = tset.terms
279 case *Union:
280 if check != nil && !check.verifyVersionf(atPos(pos), go1_18, "embedding interface element %s", u) {
281 continue
282 }
283 tset := computeUnionTypeSet(check, unionSets, pos, u)
284 if tset == &invalidTypeSet {
285 continue
286 }
287 assert(!tset.comparable)
288 assert(len(tset.methods) == 0)
289 terms = tset.terms
290 default:
291 if !isValid(u) {
292 continue
293 }
294 if check != nil && !check.verifyVersionf(atPos(pos), go1_18, "embedding non-interface type %s", typ) {
295 continue
296 }
297 terms = termlist{{false, typ}}
298 }
299
300
301
302
303 allTerms, allComparable = intersectTermLists(allTerms, allComparable, terms, comparable)
304 }
305
306 ityp.tset.comparable = allComparable
307 if len(allMethods) != 0 {
308 sortMethods(allMethods)
309 ityp.tset.methods = allMethods
310 }
311 ityp.tset.terms = allTerms
312
313 return ityp.tset
314 }
315
316
317
318
319
320
321
322 func intersectTermLists(xterms termlist, xcomp bool, yterms termlist, ycomp bool) (termlist, bool) {
323 terms := xterms.intersect(yterms)
324
325
326 comp := xcomp || ycomp
327 if comp && !terms.isAll() {
328
329 i := 0
330 for _, t := range terms {
331 assert(t.typ != nil)
332 if comparable(t.typ, false , nil, nil) {
333 terms[i] = t
334 i++
335 }
336 }
337 terms = terms[:i]
338 if !terms.isAll() {
339 comp = false
340 }
341 }
342 assert(!comp || terms.isAll())
343 return terms, comp
344 }
345
346 func sortMethods(list []*Func) {
347 sort.Sort(byUniqueMethodName(list))
348 }
349
350 func assertSortedMethods(list []*Func) {
351 if !debug {
352 panic("assertSortedMethods called outside debug mode")
353 }
354 if !sort.IsSorted(byUniqueMethodName(list)) {
355 panic("methods not sorted")
356 }
357 }
358
359
360 type byUniqueMethodName []*Func
361
362 func (a byUniqueMethodName) Len() int { return len(a) }
363 func (a byUniqueMethodName) Less(i, j int) bool { return a[i].less(&a[j].object) }
364 func (a byUniqueMethodName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
365
366
367
368
369 var invalidTypeSet _TypeSet
370
371
372
373 func computeUnionTypeSet(check *Checker, unionSets map[*Union]*_TypeSet, pos token.Pos, utyp *Union) *_TypeSet {
374 if tset, _ := unionSets[utyp]; tset != nil {
375 return tset
376 }
377
378
379 unionSets[utyp] = new(_TypeSet)
380
381 var allTerms termlist
382 for _, t := range utyp.terms {
383 var terms termlist
384 u := under(t.typ)
385 if ui, _ := u.(*Interface); ui != nil {
386
387 assert(!isTypeParam(t.typ))
388 terms = computeInterfaceTypeSet(check, pos, ui).terms
389 } else if !isValid(u) {
390 continue
391 } else {
392 if t.tilde && !Identical(t.typ, u) {
393
394
395 t = nil
396 }
397 terms = termlist{(*term)(t)}
398 }
399
400
401 allTerms = allTerms.union(terms)
402 if len(allTerms) > maxTermCount {
403 if check != nil {
404 check.errorf(atPos(pos), InvalidUnion, "cannot handle more than %d union terms (implementation limitation)", maxTermCount)
405 }
406 unionSets[utyp] = &invalidTypeSet
407 return unionSets[utyp]
408 }
409 }
410 unionSets[utyp].terms = allTerms
411
412 return unionSets[utyp]
413 }
414
View as plain text