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