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