Source file
src/go/types/predicates.go
1
2
3
4
5
6
7
8
9
10 package types
11
12 import (
13 "slices"
14 "unicode"
15 )
16
17
18 func isValid(t Type) bool { return Unalias(t) != Typ[Invalid] }
19
20
21
22
23
24 func isBoolean(t Type) bool { return isBasic(t, IsBoolean) }
25 func isInteger(t Type) bool { return isBasic(t, IsInteger) }
26 func isUnsigned(t Type) bool { return isBasic(t, IsUnsigned) }
27 func isFloat(t Type) bool { return isBasic(t, IsFloat) }
28 func isComplex(t Type) bool { return isBasic(t, IsComplex) }
29 func isNumeric(t Type) bool { return isBasic(t, IsNumeric) }
30 func isString(t Type) bool { return isBasic(t, IsString) }
31 func isIntegerOrFloat(t Type) bool { return isBasic(t, IsInteger|IsFloat) }
32 func isConstType(t Type) bool { return isBasic(t, IsConstType) }
33
34
35
36
37 func isBasic(t Type, info BasicInfo) bool {
38 u, _ := under(t).(*Basic)
39 return u != nil && u.info&info != 0
40 }
41
42
43
44
45
46
47
48 func allBoolean(t Type) bool { return allBasic(t, IsBoolean) }
49 func allInteger(t Type) bool { return allBasic(t, IsInteger) }
50 func allUnsigned(t Type) bool { return allBasic(t, IsUnsigned) }
51 func allNumeric(t Type) bool { return allBasic(t, IsNumeric) }
52 func allString(t Type) bool { return allBasic(t, IsString) }
53 func allOrdered(t Type) bool { return allBasic(t, IsOrdered) }
54 func allNumericOrString(t Type) bool { return allBasic(t, IsNumeric|IsString) }
55
56
57
58
59
60 func allBasic(t Type, info BasicInfo) bool {
61 if tpar, _ := Unalias(t).(*TypeParam); tpar != nil {
62 return tpar.is(func(t *term) bool { return t != nil && isBasic(t.typ, info) })
63 }
64 return isBasic(t, info)
65 }
66
67
68
69
70 func hasName(t Type) bool {
71 switch Unalias(t).(type) {
72 case *Basic, *Named, *TypeParam:
73 return true
74 }
75 return false
76 }
77
78
79
80
81 func isTypeLit(t Type) bool {
82 switch Unalias(t).(type) {
83 case *Named, *TypeParam:
84 return false
85 }
86 return true
87 }
88
89
90
91
92 func isTyped(t Type) bool {
93
94
95 b, _ := t.(*Basic)
96 return b == nil || b.info&IsUntyped == 0
97 }
98
99
100
101 func isUntyped(t Type) bool {
102 return !isTyped(t)
103 }
104
105
106
107 func isUntypedNumeric(t Type) bool {
108
109
110 b, _ := t.(*Basic)
111 return b != nil && b.info&IsUntyped != 0 && b.info&IsNumeric != 0
112 }
113
114
115 func IsInterface(t Type) bool {
116 _, ok := under(t).(*Interface)
117 return ok
118 }
119
120
121 func isNonTypeParamInterface(t Type) bool {
122 return !isTypeParam(t) && IsInterface(t)
123 }
124
125
126 func isTypeParam(t Type) bool {
127 _, ok := Unalias(t).(*TypeParam)
128 return ok
129 }
130
131
132
133
134
135 func hasEmptyTypeset(t Type) bool {
136 if tpar, _ := Unalias(t).(*TypeParam); tpar != nil && tpar.bound != nil {
137 iface, _ := safeUnderlying(tpar.bound).(*Interface)
138 return iface != nil && iface.tset != nil && iface.tset.IsEmpty()
139 }
140 return false
141 }
142
143
144
145
146 func isGeneric(t Type) bool {
147
148 if alias, _ := t.(*Alias); alias != nil && alias.tparams != nil && alias.targs == nil {
149 return true
150 }
151 named := asNamed(t)
152 return named != nil && named.obj != nil && named.inst == nil && named.TypeParams().Len() > 0
153 }
154
155
156 func Comparable(T Type) bool {
157 return comparableType(T, true, nil, nil)
158 }
159
160
161
162 func comparableType(T Type, dynamic bool, seen map[Type]bool, reportf func(string, ...interface{})) bool {
163 if seen[T] {
164 return true
165 }
166 if seen == nil {
167 seen = make(map[Type]bool)
168 }
169 seen[T] = true
170
171 switch t := under(T).(type) {
172 case *Basic:
173
174
175 return t.kind != UntypedNil
176 case *Pointer, *Chan:
177 return true
178 case *Struct:
179 for _, f := range t.fields {
180 if !comparableType(f.typ, dynamic, seen, nil) {
181 if reportf != nil {
182 reportf("struct containing %s cannot be compared", f.typ)
183 }
184 return false
185 }
186 }
187 return true
188 case *Array:
189 if !comparableType(t.elem, dynamic, seen, nil) {
190 if reportf != nil {
191 reportf("%s cannot be compared", t)
192 }
193 return false
194 }
195 return true
196 case *Interface:
197 if dynamic && !isTypeParam(T) || t.typeSet().IsComparable(seen) {
198 return true
199 }
200 if reportf != nil {
201 if t.typeSet().IsEmpty() {
202 reportf("empty type set")
203 } else {
204 reportf("incomparable types in type set")
205 }
206 }
207
208 }
209 return false
210 }
211
212
213 func hasNil(t Type) bool {
214 switch u := under(t).(type) {
215 case *Basic:
216 return u.kind == UnsafePointer
217 case *Slice, *Pointer, *Signature, *Map, *Chan:
218 return true
219 case *Interface:
220 return !isTypeParam(t) || underIs(t, func(u Type) bool {
221 return u != nil && hasNil(u)
222 })
223 }
224 return false
225 }
226
227
228 func samePkg(a, b *Package) bool {
229
230 if a == nil || b == nil {
231 return a == b
232 }
233
234 return a.path == b.path
235 }
236
237
238 type ifacePair struct {
239 x, y *Interface
240 prev *ifacePair
241 }
242
243 func (p *ifacePair) identical(q *ifacePair) bool {
244 return p.x == q.x && p.y == q.y || p.x == q.y && p.y == q.x
245 }
246
247
248 type comparer struct {
249 ignoreTags bool
250 ignoreInvalids bool
251 }
252
253
254 func (c *comparer) identical(x, y Type, p *ifacePair) bool {
255 x = Unalias(x)
256 y = Unalias(y)
257
258 if x == y {
259 return true
260 }
261
262 if c.ignoreInvalids && (!isValid(x) || !isValid(y)) {
263 return true
264 }
265
266 switch x := x.(type) {
267 case *Basic:
268
269
270
271 if y, ok := y.(*Basic); ok {
272 return x.kind == y.kind
273 }
274
275 case *Array:
276
277
278 if y, ok := y.(*Array); ok {
279
280
281 return (x.len < 0 || y.len < 0 || x.len == y.len) && c.identical(x.elem, y.elem, p)
282 }
283
284 case *Slice:
285
286 if y, ok := y.(*Slice); ok {
287 return c.identical(x.elem, y.elem, p)
288 }
289
290 case *Struct:
291
292
293
294
295 if y, ok := y.(*Struct); ok {
296 if x.NumFields() == y.NumFields() {
297 for i, f := range x.fields {
298 g := y.fields[i]
299 if f.embedded != g.embedded ||
300 !c.ignoreTags && x.Tag(i) != y.Tag(i) ||
301 !f.sameId(g.pkg, g.name, false) ||
302 !c.identical(f.typ, g.typ, p) {
303 return false
304 }
305 }
306 return true
307 }
308 }
309
310 case *Pointer:
311
312 if y, ok := y.(*Pointer); ok {
313 return c.identical(x.base, y.base, p)
314 }
315
316 case *Tuple:
317
318
319 if y, ok := y.(*Tuple); ok {
320 if x.Len() == y.Len() {
321 if x != nil {
322 for i, v := range x.vars {
323 w := y.vars[i]
324 if !c.identical(v.typ, w.typ, p) {
325 return false
326 }
327 }
328 }
329 return true
330 }
331 }
332
333 case *Signature:
334 y, _ := y.(*Signature)
335 if y == nil {
336 return false
337 }
338
339
340
341
342
343
344
345 if x.TypeParams().Len() != y.TypeParams().Len() {
346 return false
347 }
348
349
350
351 yparams := y.params
352 yresults := y.results
353
354 if x.TypeParams().Len() > 0 {
355
356
357 xtparams := x.TypeParams().list()
358 ytparams := y.TypeParams().list()
359
360 var targs []Type
361 for i := range xtparams {
362 targs = append(targs, x.TypeParams().At(i))
363 }
364 smap := makeSubstMap(ytparams, targs)
365
366 var check *Checker
367 ctxt := NewContext()
368
369
370 for i, xtparam := range xtparams {
371 ybound := check.subst(nopos, ytparams[i].bound, smap, nil, ctxt)
372 if !c.identical(xtparam.bound, ybound, p) {
373 return false
374 }
375 }
376
377 yparams = check.subst(nopos, y.params, smap, nil, ctxt).(*Tuple)
378 yresults = check.subst(nopos, y.results, smap, nil, ctxt).(*Tuple)
379 }
380
381 return x.variadic == y.variadic &&
382 c.identical(x.params, yparams, p) &&
383 c.identical(x.results, yresults, p)
384
385 case *Union:
386 if y, _ := y.(*Union); y != nil {
387
388
389 unionSets := make(map[*Union]*_TypeSet)
390 xset := computeUnionTypeSet(nil, unionSets, nopos, x)
391 yset := computeUnionTypeSet(nil, unionSets, nopos, y)
392 return xset.terms.equal(yset.terms)
393 }
394
395 case *Interface:
396
397
398
399
400
401
402
403 if y, ok := y.(*Interface); ok {
404 xset := x.typeSet()
405 yset := y.typeSet()
406 if xset.comparable != yset.comparable {
407 return false
408 }
409 if !xset.terms.equal(yset.terms) {
410 return false
411 }
412 a := xset.methods
413 b := yset.methods
414 if len(a) == len(b) {
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437 q := &ifacePair{x, y, p}
438 for p != nil {
439 if p.identical(q) {
440 return true
441 }
442 p = p.prev
443 }
444 if debug {
445 assertSortedMethods(a)
446 assertSortedMethods(b)
447 }
448 for i, f := range a {
449 g := b[i]
450 if f.Id() != g.Id() || !c.identical(f.typ, g.typ, q) {
451 return false
452 }
453 }
454 return true
455 }
456 }
457
458 case *Map:
459
460 if y, ok := y.(*Map); ok {
461 return c.identical(x.key, y.key, p) && c.identical(x.elem, y.elem, p)
462 }
463
464 case *Chan:
465
466
467 if y, ok := y.(*Chan); ok {
468 return x.dir == y.dir && c.identical(x.elem, y.elem, p)
469 }
470
471 case *Named:
472
473
474
475 if y := asNamed(y); y != nil {
476
477
478
479 xargs := x.TypeArgs().list()
480 yargs := y.TypeArgs().list()
481 if len(xargs) != len(yargs) {
482 return false
483 }
484 for i, xarg := range xargs {
485 if !Identical(xarg, yargs[i]) {
486 return false
487 }
488 }
489 return identicalOrigin(x, y)
490 }
491
492 case *TypeParam:
493
494
495 case nil:
496
497
498 default:
499 panic("unreachable")
500 }
501
502 return false
503 }
504
505
506 func identicalOrigin(x, y *Named) bool {
507
508 return x.Origin().obj == y.Origin().obj
509 }
510
511
512
513
514 func identicalInstance(xorig Type, xargs []Type, yorig Type, yargs []Type) bool {
515 if !slices.EqualFunc(xargs, yargs, Identical) {
516 return false
517 }
518
519 return Identical(xorig, yorig)
520 }
521
522
523
524
525 func Default(t Type) Type {
526
527
528 if t, _ := t.(*Basic); t != nil {
529 switch t.kind {
530 case UntypedBool:
531 return Typ[Bool]
532 case UntypedInt:
533 return Typ[Int]
534 case UntypedRune:
535 return universeRune
536 case UntypedFloat:
537 return Typ[Float64]
538 case UntypedComplex:
539 return Typ[Complex128]
540 case UntypedString:
541 return Typ[String]
542 }
543 }
544 return t
545 }
546
547
548
549
550
551 func maxType(x, y Type) Type {
552
553
554 if x == y {
555 return x
556 }
557 if isUntypedNumeric(x) && isUntypedNumeric(y) {
558
559 if x.(*Basic).kind > y.(*Basic).kind {
560 return x
561 }
562 return y
563 }
564 return nil
565 }
566
567
568 func clone[P *T, T any](p P) P {
569 c := *p
570 return &c
571 }
572
573
574 func isValidName(s string) bool {
575 for i, ch := range s {
576 if !(unicode.IsLetter(ch) || ch == '_' || i > 0 && unicode.IsDigit(ch)) {
577 return false
578 }
579 }
580 return true
581 }
582
View as plain text