Source file
src/go/types/typeset.go
1
2
3
4
5 package types
6
7 import (
8 "bytes"
9 "fmt"
10 "go/token"
11 "sort"
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 bytes.Buffer
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 && 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 todo []*Func
219 var seen objset
220 var allMethods []*Func
221 mpos := make(map[*Func]token.Pos)
222 addMethod := func(pos token.Pos, m *Func, explicit bool) {
223 switch other := seen.insert(m); {
224 case other == nil:
225 allMethods = append(allMethods, m)
226 mpos[m] = pos
227 case explicit:
228 if check == nil {
229 panic(fmt.Sprintf("%v: duplicate method %s", m.pos, m.name))
230 }
231
232 check.errorf(atPos(pos), _DuplicateDecl, "duplicate method %s", m.name)
233 check.errorf(atPos(mpos[other.(*Func)]), _DuplicateDecl, "\tother declaration of %s", m.name)
234 default:
235
236
237
238
239
240 if check == nil {
241
242 todo = append(todo, m, other.(*Func))
243 break
244 }
245
246 check.later(func() {
247 if !check.allowVersion(m.pkg, 1, 14) || !Identical(m.typ, other.Type()) {
248 check.errorf(atPos(pos), _DuplicateDecl, "duplicate method %s", m.name)
249 check.errorf(atPos(mpos[other.(*Func)]), _DuplicateDecl, "\tother declaration of %s", m.name)
250 }
251 })
252 }
253 }
254
255 for _, m := range ityp.methods {
256 addMethod(m.pos, m, true)
257 }
258
259
260 allTerms := allTermlist
261 allComparable := false
262 for i, typ := range ityp.embeddeds {
263
264
265
266 var pos token.Pos
267 if ityp.embedPos != nil {
268 pos = (*ityp.embedPos)[i]
269 }
270 var comparable bool
271 var terms termlist
272 switch u := under(typ).(type) {
273 case *Interface:
274
275 assert(!isTypeParam(typ))
276 tset := computeInterfaceTypeSet(check, pos, u)
277
278 if check != nil && check.isImportedConstraint(typ) && !check.allowVersion(check.pkg, 1, 18) {
279 check.errorf(atPos(pos), _UnsupportedFeature, "embedding constraint interface %s requires go1.18 or later", typ)
280 continue
281 }
282 comparable = tset.comparable
283 for _, m := range tset.methods {
284 addMethod(pos, m, false)
285 }
286 terms = tset.terms
287 case *Union:
288 if check != nil && !check.allowVersion(check.pkg, 1, 18) {
289 check.errorf(atPos(pos), _InvalidIfaceEmbed, "embedding interface element %s requires go1.18 or later", u)
290 continue
291 }
292 tset := computeUnionTypeSet(check, unionSets, pos, u)
293 if tset == &invalidTypeSet {
294 continue
295 }
296 assert(!tset.comparable)
297 assert(len(tset.methods) == 0)
298 terms = tset.terms
299 default:
300 if u == Typ[Invalid] {
301 continue
302 }
303 if check != nil && !check.allowVersion(check.pkg, 1, 18) {
304 check.errorf(atPos(pos), _InvalidIfaceEmbed, "embedding non-interface type %s requires go1.18 or later", typ)
305 continue
306 }
307 terms = termlist{{false, typ}}
308 }
309
310
311
312
313 allTerms, allComparable = intersectTermLists(allTerms, allComparable, terms, comparable)
314 }
315 ityp.embedPos = nil
316
317
318 for i := 0; i < len(todo); i += 2 {
319 m := todo[i]
320 other := todo[i+1]
321 if !Identical(m.typ, other.typ) {
322 panic(fmt.Sprintf("%v: duplicate method %s", m.pos, m.name))
323 }
324 }
325
326 ityp.tset.comparable = allComparable
327 if len(allMethods) != 0 {
328 sortMethods(allMethods)
329 ityp.tset.methods = allMethods
330 }
331 ityp.tset.terms = allTerms
332
333 return ityp.tset
334 }
335
336
337
338
339
340
341
342 func intersectTermLists(xterms termlist, xcomp bool, yterms termlist, ycomp bool) (termlist, bool) {
343 terms := xterms.intersect(yterms)
344
345
346 comp := xcomp || ycomp
347 if comp && !terms.isAll() {
348
349 i := 0
350 for _, t := range terms {
351 assert(t.typ != nil)
352 if Comparable(t.typ) {
353 terms[i] = t
354 i++
355 }
356 }
357 terms = terms[:i]
358 if !terms.isAll() {
359 comp = false
360 }
361 }
362 assert(!comp || terms.isAll())
363 return terms, comp
364 }
365
366 func sortMethods(list []*Func) {
367 sort.Sort(byUniqueMethodName(list))
368 }
369
370 func assertSortedMethods(list []*Func) {
371 if !debug {
372 panic("assertSortedMethods called outside debug mode")
373 }
374 if !sort.IsSorted(byUniqueMethodName(list)) {
375 panic("methods not sorted")
376 }
377 }
378
379
380 type byUniqueMethodName []*Func
381
382 func (a byUniqueMethodName) Len() int { return len(a) }
383 func (a byUniqueMethodName) Less(i, j int) bool { return a[i].Id() < a[j].Id() }
384 func (a byUniqueMethodName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
385
386
387
388
389 var invalidTypeSet _TypeSet
390
391
392
393 func computeUnionTypeSet(check *Checker, unionSets map[*Union]*_TypeSet, pos token.Pos, utyp *Union) *_TypeSet {
394 if tset, _ := unionSets[utyp]; tset != nil {
395 return tset
396 }
397
398
399 unionSets[utyp] = new(_TypeSet)
400
401 var allTerms termlist
402 for _, t := range utyp.terms {
403 var terms termlist
404 u := under(t.typ)
405 if ui, _ := u.(*Interface); ui != nil {
406
407 assert(!isTypeParam(t.typ))
408 terms = computeInterfaceTypeSet(check, pos, ui).terms
409 } else if u == Typ[Invalid] {
410 continue
411 } else {
412 if t.tilde && !Identical(t.typ, u) {
413
414
415 t = nil
416 }
417 terms = termlist{(*term)(t)}
418 }
419
420
421 allTerms = allTerms.union(terms)
422 if len(allTerms) > maxTermCount {
423 if check != nil {
424 check.errorf(atPos(pos), _InvalidUnion, "cannot handle more than %d union terms (implementation limitation)", maxTermCount)
425 }
426 unionSets[utyp] = &invalidTypeSet
427 return unionSets[utyp]
428 }
429 }
430 unionSets[utyp].terms = allTerms
431
432 return unionSets[utyp]
433 }
434
View as plain text