1 // Copyright 2013 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // This file implements printing of types.
15 // A Qualifier controls how named package-level objects are printed in
16 // calls to TypeString, ObjectString, and SelectionString.
18 // These three formatting routines call the Qualifier for each
19 // package-level object O, and if the Qualifier returns a non-empty
20 // string p, the object is printed in the form p.O.
21 // If it returns an empty string, only the object name O is printed.
23 // Using a nil Qualifier is equivalent to using (*Package).Path: the
24 // object is qualified by the import path, e.g., "encoding/json.Marshal".
26 type Qualifier func(*Package) string
28 // RelativeTo returns a Qualifier that fully qualifies members of
29 // all packages other than pkg.
30 func RelativeTo(pkg *Package) Qualifier {
34 return func(other *Package) string {
36 return "" // same package; unqualified
42 // TypeString returns the string representation of typ.
43 // The Qualifier controls the printing of
44 // package-level objects, and may be nil.
45 func TypeString(typ Type, qf Qualifier) string {
47 WriteType(&buf, typ, qf)
51 // WriteType writes the string representation of typ to buf.
52 // The Qualifier controls the printing of
53 // package-level objects, and may be nil.
54 func WriteType(buf *bytes.Buffer, typ Type, qf Qualifier) {
55 newTypeWriter(buf, qf).typ(typ)
58 // instanceMarker is the prefix for an instantiated type in unexpanded form.
59 const instanceMarker = '#'
61 type typeWriter struct {
68 func newTypeWriter(buf *bytes.Buffer, qf Qualifier) *typeWriter {
69 return &typeWriter{buf, make(map[Type]bool), qf, false}
72 func newTypeHasher(buf *bytes.Buffer) *typeWriter {
73 return &typeWriter{buf, make(map[Type]bool), nil, true}
76 func (w *typeWriter) byte(b byte) { w.buf.WriteByte(b) }
77 func (w *typeWriter) string(s string) { w.buf.WriteString(s) }
78 func (w *typeWriter) writef(format string, args ...interface{}) { fmt.Fprintf(w.buf, format, args...) }
80 func (w *typeWriter) typ(typ Type) {
82 w.writef("○%T", goTypeName(typ)) // cycle to typ
86 defer delete(w.seen, typ)
88 switch t := typ.(type) {
93 // exported basic types go into package unsafe
94 // (currently this is just unsafe.Pointer)
95 if isExported(t.name) {
96 if obj, _ := Unsafe.scope.Lookup(t.name).(*TypeName); obj != nil {
104 w.writef("[%d]", t.len)
113 for i, f := range t.fields {
117 // This doesn't do the right thing for embedded type
118 // aliases where we should print the alias name, not
119 // the aliased type (see issue #44410).
125 if tag := t.Tag(i); tag != "" {
143 // Unions only appear as (syntactic) embedded elements
144 // in interfaces and syntactically cannot be empty.
148 for i, t := range t.terms {
159 w.string("interface{")
161 for _, m := range t.methods {
167 w.signature(m.typ.(*Signature))
169 for _, typ := range t.embeddeds {
190 // chan (<-chan T) requires parentheses
191 if c, _ := t.elem.(*Chan); c != nil && c.dir == RecvOnly {
211 // Instance markers indicate unexpanded instantiated
212 // types. Write them to aid debugging, but don't write
213 // them when we need an instance hash: whether a type
214 // is fully expanded or not doesn't matter for identity.
215 if !w.hash && t.instPos != nil {
216 w.byte(instanceMarker)
221 w.typeList(t.targs.list())
222 } else if t.TParams().Len() != 0 {
223 // parameterized type
224 w.tParamList(t.TParams().list())
230 // Optionally write out package for typeparams (like Named).
231 // TODO(danscales): this is required for import/export, so
232 // we maybe need a separate function that won't be changed
233 // for debugging purposes.
234 if t.obj.pkg != nil {
235 writePackage(w.buf, t.obj.pkg, w.qf)
239 w.string(s + subscript(t.id))
245 // For externally defined implementations of Type.
246 // Note: In this case cycles won't be caught.
251 func (w *typeWriter) typeList(list []Type) {
253 for i, typ := range list {
262 func (w *typeWriter) tParamList(list []*TypeParam) {
265 for i, tpar := range list {
266 // Determine the type parameter and its constraint.
267 // list is expected to hold type parameter names,
268 // but don't crash if that's not the case.
271 bound = tpar.bound // should not be nil but we want to see it if it is
276 // bound changed - write previous one before advancing
287 w.string(tpar.obj.name)
297 func (w *typeWriter) typeName(obj *TypeName) {
299 assert(!w.hash) // we need an object for type hashing
300 w.string("<Named w/o object>")
304 writePackage(w.buf, obj.pkg, w.qf)
309 // For local defined types, use the (original!) TypeName's scope
310 // numbers to disambiguate.
311 if typ, _ := obj.typ.(*Named); typ != nil {
312 // TODO(gri) Figure out why typ.orig != typ.orig.orig sometimes
313 // and whether the loop can iterate more than twice.
314 // (It seems somehow connected to instance types.)
315 for typ.orig != typ {
318 w.writeScopeNumbers(typ.obj.parent)
323 // writeScopeNumbers writes the number sequence for this scope to buf
324 // in the form ".i.j.k" where i, j, k, etc. stand for scope numbers.
325 // If a scope is nil or has no parent (such as a package scope), nothing
327 func (w *typeWriter) writeScopeNumbers(s *Scope) {
328 if s != nil && s.number > 0 {
329 w.writeScopeNumbers(s.parent)
330 w.writef(".%d", s.number)
334 func (w *typeWriter) tuple(tup *Tuple, variadic bool) {
337 for i, v := range tup.vars {
341 // parameter names are ignored for type identity and thus type hashes
342 if !w.hash && v.name != "" {
347 if variadic && i == len(tup.vars)-1 {
348 if s, ok := typ.(*Slice); ok {
353 // append(s, "foo"...) leads to signature func([]byte, string...)
354 if t := asBasic(typ); t == nil || t.kind != String {
355 panic("expected string type")
368 // WriteSignature writes the representation of the signature sig to buf,
369 // without a leading "func" keyword.
370 // The Qualifier controls the printing of
371 // package-level objects, and may be nil.
372 func WriteSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier) {
373 newTypeWriter(buf, qf).signature(sig)
376 func (w *typeWriter) signature(sig *Signature) {
377 if sig.TParams().Len() != 0 {
378 w.tParamList(sig.TParams().list())
381 w.tuple(sig.params, sig.variadic)
383 n := sig.results.Len()
390 if n == 1 && (w.hash || sig.results.vars[0].name == "") {
391 // single unnamed result (if type hashing, name must be ignored)
392 w.typ(sig.results.vars[0].typ)
396 // multiple or named result(s)
397 w.tuple(sig.results, false)
400 // subscript returns the decimal (utf8) representation of x using subscript digits.
401 func subscript(x uint64) string {
402 const w = len("₀") // all digits 0...9 have the same utf8 width
407 utf8.EncodeRune(buf[i:], '₀'+rune(x%10)) // '₀' == U+2080
413 return string(buf[i:])