1
2
3
4
5 package types
6
7 import (
8 "bytes"
9 "encoding/binary"
10 "fmt"
11 "strconv"
12 "sync"
13
14 "cmd/compile/internal/base"
15 "cmd/internal/hash"
16 )
17
18
19 var BuiltinPkg *Pkg
20
21
22 var LocalPkg *Pkg
23
24
25 var UnsafePkg *Pkg
26
27
28 var BlankSym *Sym
29
30
31
32
33
34 var NumImport = make(map[string]int)
35
36
37
38
39
40
41 type fmtMode int
42
43 const (
44 fmtGo fmtMode = iota
45 fmtDebug
46 fmtTypeID
47 fmtTypeIDName
48 )
49
50
51
52
53
54
55
56
57
58 func (s *Sym) Format(f fmt.State, verb rune) {
59 mode := fmtGo
60 switch verb {
61 case 'v', 'S':
62 if verb == 'v' && f.Flag('+') {
63 mode = fmtDebug
64 }
65 fmt.Fprint(f, sconv(s, verb, mode))
66
67 default:
68 fmt.Fprintf(f, "%%!%c(*types.Sym=%p)", verb, s)
69 }
70 }
71
72 func (s *Sym) String() string {
73 return sconv(s, 0, fmtGo)
74 }
75
76
77
78 func sconv(s *Sym, verb rune, mode fmtMode) string {
79 if verb == 'L' {
80 panic("linksymfmt")
81 }
82
83 if s == nil {
84 return "<S>"
85 }
86
87 q := pkgqual(s.Pkg, verb, mode)
88 if q == "" {
89 return s.Name
90 }
91
92 buf := fmtBufferPool.Get().(*bytes.Buffer)
93 buf.Reset()
94 defer fmtBufferPool.Put(buf)
95
96 buf.WriteString(q)
97 buf.WriteByte('.')
98 buf.WriteString(s.Name)
99 return InternString(buf.Bytes())
100 }
101
102 func sconv2(b *bytes.Buffer, s *Sym, verb rune, mode fmtMode) {
103 if verb == 'L' {
104 panic("linksymfmt")
105 }
106 if s == nil {
107 b.WriteString("<S>")
108 return
109 }
110
111 symfmt(b, s, verb, mode)
112 }
113
114 func symfmt(b *bytes.Buffer, s *Sym, verb rune, mode fmtMode) {
115 name := s.Name
116 if q := pkgqual(s.Pkg, verb, mode); q != "" {
117 b.WriteString(q)
118 b.WriteByte('.')
119 }
120 b.WriteString(name)
121 }
122
123
124
125
126 func pkgqual(pkg *Pkg, verb rune, mode fmtMode) string {
127 if pkg == nil {
128 return ""
129 }
130 if verb != 'S' {
131 switch mode {
132 case fmtGo:
133 if pkg == BuiltinPkg || pkg == LocalPkg {
134 return ""
135 }
136
137
138 if pkg.Name != "" && NumImport[pkg.Name] > 1 {
139 return strconv.Quote(pkg.Path)
140 }
141 return pkg.Name
142
143 case fmtDebug:
144 return pkg.Name
145
146 case fmtTypeIDName:
147
148 return pkg.Name
149
150 case fmtTypeID:
151
152 return pkg.Prefix
153 }
154 }
155
156 return ""
157 }
158
159
160
161 var BasicTypeNames = []string{
162 TINT: "int",
163 TUINT: "uint",
164 TINT8: "int8",
165 TUINT8: "uint8",
166 TINT16: "int16",
167 TUINT16: "uint16",
168 TINT32: "int32",
169 TUINT32: "uint32",
170 TINT64: "int64",
171 TUINT64: "uint64",
172 TUINTPTR: "uintptr",
173 TFLOAT32: "float32",
174 TFLOAT64: "float64",
175 TCOMPLEX64: "complex64",
176 TCOMPLEX128: "complex128",
177 TBOOL: "bool",
178 TANY: "any",
179 TSTRING: "string",
180 TNIL: "nil",
181 TIDEAL: "untyped number",
182 TBLANK: "blank",
183 }
184
185 var fmtBufferPool = sync.Pool{
186 New: func() interface{} {
187 return new(bytes.Buffer)
188 },
189 }
190
191
192
193
194
195
196
197
198
199 func (t *Type) Format(s fmt.State, verb rune) {
200 mode := fmtGo
201 switch verb {
202 case 'v', 'S', 'L':
203 if verb == 'v' && s.Flag('+') {
204 mode = fmtDebug
205 }
206 if verb == 'S' && s.Flag('-') {
207 mode = fmtTypeID
208 }
209 fmt.Fprint(s, tconv(t, verb, mode))
210 default:
211 fmt.Fprintf(s, "%%!%c(*Type=%p)", verb, t)
212 }
213 }
214
215
216 func (t *Type) String() string {
217 return tconv(t, 0, fmtGo)
218 }
219
220
221
222
223
224
225
226
227 func (t *Type) LinkString() string {
228 return tconv(t, 0, fmtTypeID)
229 }
230
231
232
233
234
235
236
237
238
239 func (t *Type) NameString() string {
240 return tconv(t, 0, fmtTypeIDName)
241 }
242
243 func tconv(t *Type, verb rune, mode fmtMode) string {
244 buf := fmtBufferPool.Get().(*bytes.Buffer)
245 buf.Reset()
246 defer fmtBufferPool.Put(buf)
247
248 tconv2(buf, t, verb, mode, nil)
249 return InternString(buf.Bytes())
250 }
251
252
253
254
255
256 func tconv2(b *bytes.Buffer, t *Type, verb rune, mode fmtMode, visited map[*Type]int) {
257 if off, ok := visited[t]; ok {
258
259
260 fmt.Fprintf(b, "@%d", off)
261 return
262 }
263 if t == nil {
264 b.WriteString("<T>")
265 return
266 }
267 if t.Kind() == TSSA {
268 b.WriteString(t.extra.(string))
269 return
270 }
271 if t.Kind() == TTUPLE {
272 b.WriteString(t.FieldType(0).String())
273 b.WriteByte(',')
274 b.WriteString(t.FieldType(1).String())
275 return
276 }
277
278 if t.Kind() == TRESULTS {
279 tys := t.extra.(*Results).Types
280 for i, et := range tys {
281 if i > 0 {
282 b.WriteByte(',')
283 }
284 b.WriteString(et.String())
285 }
286 return
287 }
288
289 if t == AnyType || t == ByteType || t == RuneType {
290
291 switch mode {
292 case fmtTypeIDName, fmtTypeID:
293 t = Types[t.Kind()]
294 default:
295 sconv2(b, t.Sym(), 'S', mode)
296 return
297 }
298 }
299 if t == ErrorType {
300 b.WriteString("error")
301 return
302 }
303
304
305 if verb != 'L' && t.Sym() != nil && t != Types[t.Kind()] {
306
307 if verb != 'S' {
308 verb = 'v'
309 }
310
311
312
313
314 sym := t.Sym()
315 if mode != fmtTypeID {
316 base, _ := SplitVargenSuffix(sym.Name)
317 if len(base) < len(sym.Name) {
318 sym = &Sym{Pkg: sym.Pkg, Name: base}
319 }
320 }
321 sconv2(b, sym, verb, mode)
322 return
323 }
324
325 if int(t.Kind()) < len(BasicTypeNames) && BasicTypeNames[t.Kind()] != "" {
326 var name string
327 switch t {
328 case UntypedBool:
329 name = "untyped bool"
330 case UntypedString:
331 name = "untyped string"
332 case UntypedInt:
333 name = "untyped int"
334 case UntypedRune:
335 name = "untyped rune"
336 case UntypedFloat:
337 name = "untyped float"
338 case UntypedComplex:
339 name = "untyped complex"
340 default:
341 name = BasicTypeNames[t.Kind()]
342 }
343 b.WriteString(name)
344 return
345 }
346
347 if mode == fmtDebug {
348 b.WriteString(t.Kind().String())
349 b.WriteByte('-')
350 tconv2(b, t, 'v', fmtGo, visited)
351 return
352 }
353
354
355
356
357
358
359
360
361 if visited == nil {
362 visited = map[*Type]int{}
363 }
364 visited[t] = b.Len()
365 defer delete(visited, t)
366
367 switch t.Kind() {
368 case TPTR:
369 b.WriteByte('*')
370 switch mode {
371 case fmtTypeID, fmtTypeIDName:
372 if verb == 'S' {
373 tconv2(b, t.Elem(), 'S', mode, visited)
374 return
375 }
376 }
377 tconv2(b, t.Elem(), 'v', mode, visited)
378
379 case TARRAY:
380 b.WriteByte('[')
381 b.WriteString(strconv.FormatInt(t.NumElem(), 10))
382 b.WriteByte(']')
383 tconv2(b, t.Elem(), 0, mode, visited)
384
385 case TSLICE:
386 b.WriteString("[]")
387 tconv2(b, t.Elem(), 0, mode, visited)
388
389 case TCHAN:
390 switch t.ChanDir() {
391 case Crecv:
392 b.WriteString("<-chan ")
393 tconv2(b, t.Elem(), 0, mode, visited)
394 case Csend:
395 b.WriteString("chan<- ")
396 tconv2(b, t.Elem(), 0, mode, visited)
397 default:
398 b.WriteString("chan ")
399 if t.Elem() != nil && t.Elem().IsChan() && t.Elem().Sym() == nil && t.Elem().ChanDir() == Crecv {
400 b.WriteByte('(')
401 tconv2(b, t.Elem(), 0, mode, visited)
402 b.WriteByte(')')
403 } else {
404 tconv2(b, t.Elem(), 0, mode, visited)
405 }
406 }
407
408 case TMAP:
409 b.WriteString("map[")
410 tconv2(b, t.Key(), 0, mode, visited)
411 b.WriteByte(']')
412 tconv2(b, t.Elem(), 0, mode, visited)
413
414 case TINTER:
415 if t.IsEmptyInterface() {
416 b.WriteString("interface {}")
417 break
418 }
419 b.WriteString("interface {")
420 for i, f := range t.AllMethods() {
421 if i != 0 {
422 b.WriteByte(';')
423 }
424 b.WriteByte(' ')
425 switch {
426 case f.Sym == nil:
427
428
429 break
430 case IsExported(f.Sym.Name):
431 sconv2(b, f.Sym, 'S', mode)
432 default:
433 if mode != fmtTypeIDName {
434 mode = fmtTypeID
435 }
436 sconv2(b, f.Sym, 'v', mode)
437 }
438 tconv2(b, f.Type, 'S', mode, visited)
439 }
440 if len(t.AllMethods()) != 0 {
441 b.WriteByte(' ')
442 }
443 b.WriteByte('}')
444
445 case TFUNC:
446 if verb == 'S' {
447
448 } else {
449 if t.Recv() != nil {
450 b.WriteString("method")
451 formatParams(b, t.Recvs(), mode, visited)
452 b.WriteByte(' ')
453 }
454 b.WriteString("func")
455 }
456 formatParams(b, t.Params(), mode, visited)
457
458 switch t.NumResults() {
459 case 0:
460
461
462 case 1:
463 b.WriteByte(' ')
464 tconv2(b, t.Result(0).Type, 0, mode, visited)
465
466 default:
467 b.WriteByte(' ')
468 formatParams(b, t.Results(), mode, visited)
469 }
470
471 case TSTRUCT:
472 if m := t.StructType().Map; m != nil {
473 mt := m.MapType()
474
475
476 switch t {
477 case mt.OldBucket:
478 b.WriteString("map.bucket[")
479 case mt.SwissGroup:
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 func TypeHash(t *Type) uint32 {
647 p := t.LinkString()
648
649
650 h := hash.Sum16([]byte(p))
651 return binary.LittleEndian.Uint32(h[:4])
652 }
653
View as plain text