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