1
2
3
4
5 package types
6
7 import (
8 "bytes"
9 "encoding/binary"
10 "fmt"
11 "strconv"
12 "strings"
13 "sync"
14
15 "cmd/compile/internal/base"
16 "cmd/internal/hash"
17 )
18
19
20 var BuiltinPkg *Pkg
21
22
23 var LocalPkg *Pkg
24
25
26 var UnsafePkg *Pkg
27
28
29 var BlankSym *Sym
30
31
32
33
34
35 var NumImport = make(map[string]int)
36
37
38
39
40
41
42 type fmtMode int
43
44 const (
45 fmtGo fmtMode = iota
46 fmtDebug
47 fmtTypeID
48 fmtTypeIDName
49 )
50
51
52
53
54
55
56
57
58
59 func (s *Sym) Format(f fmt.State, verb rune) {
60 mode := fmtGo
61 switch verb {
62 case 'v', 'S':
63 if verb == 'v' && f.Flag('+') {
64 mode = fmtDebug
65 }
66 fmt.Fprint(f, sconv(s, verb, mode))
67
68 default:
69 fmt.Fprintf(f, "%%!%c(*types.Sym=%p)", verb, s)
70 }
71 }
72
73 func (s *Sym) String() string {
74 return sconv(s, 0, fmtGo)
75 }
76
77
78
79 func sconv(s *Sym, verb rune, mode fmtMode) string {
80 if verb == 'L' {
81 panic("linksymfmt")
82 }
83
84 if s == nil {
85 return "<S>"
86 }
87
88 q := pkgqual(s.Pkg, verb, mode)
89 if q == "" {
90 return s.Name
91 }
92
93 buf := fmtBufferPool.Get().(*bytes.Buffer)
94 buf.Reset()
95 defer fmtBufferPool.Put(buf)
96
97 buf.WriteString(q)
98 buf.WriteByte('.')
99 buf.WriteString(s.Name)
100 return InternString(buf.Bytes())
101 }
102
103 func sconv2(b *bytes.Buffer, s *Sym, verb rune, mode fmtMode) {
104 if verb == 'L' {
105 panic("linksymfmt")
106 }
107 if s == nil {
108 b.WriteString("<S>")
109 return
110 }
111
112 symfmt(b, s, verb, mode)
113 }
114
115 func symfmt(b *bytes.Buffer, s *Sym, verb rune, mode fmtMode) {
116 name := s.Name
117 if q := pkgqual(s.Pkg, verb, mode); q != "" {
118 b.WriteString(q)
119 b.WriteByte('.')
120 }
121 b.WriteString(name)
122 }
123
124
125
126
127 func pkgqual(pkg *Pkg, verb rune, mode fmtMode) string {
128 if pkg == nil {
129 return ""
130 }
131 if verb != 'S' {
132 switch mode {
133 case fmtGo:
134 if pkg == BuiltinPkg || pkg == LocalPkg {
135 return ""
136 }
137
138
139 if pkg.Name != "" && NumImport[pkg.Name] > 1 {
140 return strconv.Quote(pkg.Path)
141 }
142 return pkg.Name
143
144 case fmtDebug:
145 return pkg.Name
146
147 case fmtTypeIDName:
148
149 return pkg.Name
150
151 case fmtTypeID:
152
153 return pkg.Prefix
154 }
155 }
156
157 return ""
158 }
159
160
161
162 var BasicTypeNames = []string{
163 TINT: "int",
164 TUINT: "uint",
165 TINT8: "int8",
166 TUINT8: "uint8",
167 TINT16: "int16",
168 TUINT16: "uint16",
169 TINT32: "int32",
170 TUINT32: "uint32",
171 TINT64: "int64",
172 TUINT64: "uint64",
173 TUINTPTR: "uintptr",
174 TFLOAT32: "float32",
175 TFLOAT64: "float64",
176 TCOMPLEX64: "complex64",
177 TCOMPLEX128: "complex128",
178 TBOOL: "bool",
179 TANY: "any",
180 TSTRING: "string",
181 TNIL: "nil",
182 TIDEAL: "untyped number",
183 TBLANK: "blank",
184 }
185
186 var fmtBufferPool = sync.Pool{
187 New: func() any {
188 return new(bytes.Buffer)
189 },
190 }
191
192
193
194
195
196
197
198
199
200 func (t *Type) Format(s fmt.State, verb rune) {
201 mode := fmtGo
202 switch verb {
203 case 'v', 'S', 'L':
204 if verb == 'v' && s.Flag('+') {
205 mode = fmtDebug
206 }
207 if verb == 'S' && s.Flag('-') {
208 mode = fmtTypeID
209 }
210 fmt.Fprint(s, tconv(t, verb, mode))
211 default:
212 fmt.Fprintf(s, "%%!%c(*Type=%p)", verb, t)
213 }
214 }
215
216
217 func (t *Type) String() string {
218 return tconv(t, 0, fmtGo)
219 }
220
221
222
223
224
225
226
227
228 func (t *Type) LinkString() string {
229 return tconv(t, 0, fmtTypeID)
230 }
231
232
233
234
235
236
237
238
239
240 func (t *Type) NameString() string {
241 return tconv(t, 0, fmtTypeIDName)
242 }
243
244 func tconv(t *Type, verb rune, mode fmtMode) string {
245 buf := fmtBufferPool.Get().(*bytes.Buffer)
246 buf.Reset()
247 defer fmtBufferPool.Put(buf)
248
249 tconv2(buf, t, verb, mode, nil)
250 return InternString(buf.Bytes())
251 }
252
253
254
255
256
257 func tconv2(b *bytes.Buffer, t *Type, verb rune, mode fmtMode, visited map[*Type]int) {
258 if off, ok := visited[t]; ok {
259
260
261 fmt.Fprintf(b, "@%d", off)
262 return
263 }
264 if t == nil {
265 b.WriteString("<T>")
266 return
267 }
268 if t.Kind() == TSSA {
269 b.WriteString(t.extra.(string))
270 return
271 }
272 if t.Kind() == TTUPLE {
273 b.WriteString(t.FieldType(0).String())
274 b.WriteByte(',')
275 b.WriteString(t.FieldType(1).String())
276 return
277 }
278
279 if t.Kind() == TRESULTS {
280 tys := t.extra.(*Results).Types
281 for i, et := range tys {
282 if i > 0 {
283 b.WriteByte(',')
284 }
285 b.WriteString(et.String())
286 }
287 return
288 }
289
290 if t == AnyType || t == ByteType || t == RuneType {
291
292 switch mode {
293 case fmtTypeIDName, fmtTypeID:
294 t = Types[t.Kind()]
295 default:
296 sconv2(b, t.Sym(), 'S', mode)
297 return
298 }
299 }
300 if t == ErrorType {
301 b.WriteString("error")
302 return
303 }
304
305
306 if verb != 'L' && t.Sym() != nil && t != Types[t.Kind()] {
307
308 if verb != 'S' {
309 verb = 'v'
310 }
311
312
313
314
315 sym := t.Sym()
316 if mode != fmtTypeID {
317 base, _ := SplitVargenSuffix(sym.Name)
318 if len(base) < len(sym.Name) {
319 sym = &Sym{Pkg: sym.Pkg, Name: base}
320 }
321 }
322 sconv2(b, sym, verb, mode)
323 return
324 }
325
326 if int(t.Kind()) < len(BasicTypeNames) && BasicTypeNames[t.Kind()] != "" {
327 var name string
328 switch t {
329 case UntypedBool:
330 name = "untyped bool"
331 case UntypedString:
332 name = "untyped string"
333 case UntypedInt:
334 name = "untyped int"
335 case UntypedRune:
336 name = "untyped rune"
337 case UntypedFloat:
338 name = "untyped float"
339 case UntypedComplex:
340 name = "untyped complex"
341 default:
342 name = BasicTypeNames[t.Kind()]
343 }
344 b.WriteString(name)
345 return
346 }
347
348 if mode == fmtDebug {
349 b.WriteString(t.Kind().String())
350 b.WriteByte('-')
351 tconv2(b, t, 'v', fmtGo, visited)
352 return
353 }
354
355
356
357
358
359
360
361
362 if visited == nil {
363 visited = map[*Type]int{}
364 }
365 visited[t] = b.Len()
366 defer delete(visited, t)
367
368 switch t.Kind() {
369 case TPTR:
370 b.WriteByte('*')
371 switch mode {
372 case fmtTypeID, fmtTypeIDName:
373 if verb == 'S' {
374 tconv2(b, t.Elem(), 'S', mode, visited)
375 return
376 }
377 }
378 tconv2(b, t.Elem(), 'v', mode, visited)
379
380 case TARRAY:
381 b.WriteByte('[')
382 b.WriteString(strconv.FormatInt(t.NumElem(), 10))
383 b.WriteByte(']')
384 tconv2(b, t.Elem(), 0, mode, visited)
385
386 case TSLICE:
387 b.WriteString("[]")
388 tconv2(b, t.Elem(), 0, mode, visited)
389
390 case TCHAN:
391 switch t.ChanDir() {
392 case Crecv:
393 b.WriteString("<-chan ")
394 tconv2(b, t.Elem(), 0, mode, visited)
395 case Csend:
396 b.WriteString("chan<- ")
397 tconv2(b, t.Elem(), 0, mode, visited)
398 default:
399 b.WriteString("chan ")
400 if t.Elem() != nil && t.Elem().IsChan() && t.Elem().Sym() == nil && t.Elem().ChanDir() == Crecv {
401 b.WriteByte('(')
402 tconv2(b, t.Elem(), 0, mode, visited)
403 b.WriteByte(')')
404 } else {
405 tconv2(b, t.Elem(), 0, mode, visited)
406 }
407 }
408
409 case TMAP:
410 b.WriteString("map[")
411 tconv2(b, t.Key(), 0, mode, visited)
412 b.WriteByte(']')
413 tconv2(b, t.Elem(), 0, mode, visited)
414
415 case TINTER:
416 if t.IsEmptyInterface() {
417 b.WriteString("interface {}")
418 break
419 }
420 b.WriteString("interface {")
421 for i, f := range t.AllMethods() {
422 if i != 0 {
423 b.WriteByte(';')
424 }
425 b.WriteByte(' ')
426 switch {
427 case f.Sym == nil:
428
429
430 break
431 case IsExported(f.Sym.Name):
432 sconv2(b, f.Sym, 'S', mode)
433 default:
434 smode := mode
435 if mode != fmtTypeIDName {
436 smode = fmtTypeID
437 }
438 sconv2(b, f.Sym, 'v', smode)
439 }
440 tconv2(b, f.Type, 'S', mode, visited)
441 }
442 if len(t.AllMethods()) != 0 {
443 b.WriteByte(' ')
444 }
445 b.WriteByte('}')
446
447 case TFUNC:
448 if verb == 'S' {
449
450 } else {
451 if t.Recv() != nil {
452 b.WriteString("method")
453 formatParams(b, t.Recvs(), mode, visited)
454 b.WriteByte(' ')
455 }
456 b.WriteString("func")
457 }
458 formatParams(b, t.Params(), mode, visited)
459
460 switch t.NumResults() {
461 case 0:
462
463
464 case 1:
465 b.WriteByte(' ')
466 tconv2(b, t.Result(0).Type, 0, mode, visited)
467
468 default:
469 b.WriteByte(' ')
470 formatParams(b, t.Results(), mode, visited)
471 }
472
473 case TSTRUCT:
474 if m := t.StructType().Map; m != nil {
475 mt := m.MapType()
476
477
478 switch t {
479 case mt.Group:
480 b.WriteString("map.group[")
481 default:
482 base.Fatalf("unknown internal map type")
483 }
484 tconv2(b, m.Key(), 0, mode, visited)
485 b.WriteByte(']')
486 tconv2(b, m.Elem(), 0, mode, visited)
487 break
488 }
489
490 b.WriteString("struct {")
491 for i, f := range t.Fields() {
492 if i != 0 {
493 b.WriteByte(';')
494 }
495 b.WriteByte(' ')
496 fldconv(b, f, 'L', mode, visited, false)
497 }
498 if t.NumFields() != 0 {
499 b.WriteByte(' ')
500 }
501 b.WriteByte('}')
502
503 case TFORW:
504 b.WriteString("undefined")
505 if t.Sym() != nil {
506 b.WriteByte(' ')
507 sconv2(b, t.Sym(), 'v', mode)
508 }
509
510 case TUNSAFEPTR:
511 b.WriteString("unsafe.Pointer")
512
513 case Txxx:
514 b.WriteString("Txxx")
515
516 default:
517
518 b.WriteString(t.Kind().String())
519 b.WriteString(" <")
520 sconv2(b, t.Sym(), 'v', mode)
521 b.WriteString(">")
522
523 }
524 }
525
526 func formatParams(b *bytes.Buffer, params []*Field, mode fmtMode, visited map[*Type]int) {
527 b.WriteByte('(')
528 fieldVerb := 'v'
529 switch mode {
530 case fmtTypeID, fmtTypeIDName, fmtGo:
531
532 fieldVerb = 'S'
533 }
534 for i, param := range params {
535 if i != 0 {
536 b.WriteString(", ")
537 }
538 fldconv(b, param, fieldVerb, mode, visited, true)
539 }
540 b.WriteByte(')')
541 }
542
543 func fldconv(b *bytes.Buffer, f *Field, verb rune, mode fmtMode, visited map[*Type]int, isParam bool) {
544 if f == nil {
545 b.WriteString("<T>")
546 return
547 }
548
549 var name string
550 nameSep := " "
551 if verb != 'S' {
552 s := f.Sym
553
554
555
556
557
558
559
560
561
562
563
564
565 if f.Embedded != 0 {
566 if mode == fmtTypeID {
567 nameSep = " = "
568
569
570
571
572
573 typ := f.Type
574 if typ.IsPtr() {
575 base.Assertf(typ.Sym() == nil, "embedded pointer type has name: %L", typ)
576 typ = typ.Elem()
577 }
578 tsym := typ.Sym()
579
580
581
582
583 if tsym != nil && (s == tsym || IsExported(tsym.Name) && s.Name == tsym.Name) {
584 s = nil
585 }
586 } else {
587
588
589
590 s = nil
591 }
592 }
593
594 if s != nil {
595 if isParam {
596 name = fmt.Sprint(f.Nname)
597 } else if verb == 'L' {
598 name = s.Name
599 if !IsExported(name) && mode != fmtTypeIDName {
600 name = sconv(s, 0, mode)
601 }
602 } else {
603 name = sconv(s, 0, mode)
604 }
605 }
606 }
607
608 if name != "" {
609 b.WriteString(name)
610 b.WriteString(nameSep)
611 }
612
613 if f.IsDDD() {
614 var et *Type
615 if f.Type != nil {
616 et = f.Type.Elem()
617 }
618 b.WriteString("...")
619 tconv2(b, et, 0, mode, visited)
620 } else {
621 tconv2(b, f.Type, 0, mode, visited)
622 }
623
624 if verb != 'S' && !isParam && f.Note != "" {
625 b.WriteString(" ")
626 b.WriteString(strconv.Quote(f.Note))
627 }
628 }
629
630
631
632 func SplitVargenSuffix(name string) (base, suffix string) {
633 i := len(name)
634 for i > 0 && name[i-1] >= '0' && name[i-1] <= '9' {
635 i--
636 }
637 const dot = "·"
638 if i >= len(dot) && name[i-len(dot):i] == dot {
639 i -= len(dot)
640 return name[:i], name[i:]
641 }
642 return name, ""
643 }
644
645
646
647 func SplitMethSuffix(name string) (tname, suffix string) {
648 i := strings.LastIndex(name, ".")
649 if i >= 0 {
650 return name[:i], name[i:]
651 }
652 return name, ""
653 }
654
655
656 func TypeHash(t *Type) uint32 {
657 p := t.LinkString()
658
659
660 h := hash.Sum32([]byte(p))
661 return binary.LittleEndian.Uint32(h[:4])
662 }
663
View as plain text