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 {
67 func newTypeWriter(buf *bytes.Buffer, qf Qualifier) *typeWriter {
68 return &typeWriter{buf, make(map[Type]bool), qf}
71 func (w *typeWriter) byte(b byte) { w.buf.WriteByte(b) }
72 func (w *typeWriter) string(s string) { w.buf.WriteString(s) }
73 func (w *typeWriter) writef(format string, args ...interface{}) { fmt.Fprintf(w.buf, format, args...) }
75 func (w *typeWriter) typ(typ Type) {
77 w.writef("○%T", goTypeName(typ)) // cycle to typ
81 defer delete(w.seen, typ)
83 switch t := typ.(type) {
88 // exported basic types go into package unsafe
89 // (currently this is just unsafe.Pointer)
90 if isExported(t.name) {
91 if obj, _ := Unsafe.scope.Lookup(t.name).(*TypeName); obj != nil {
99 w.writef("[%d]", t.len)
108 for i, f := range t.fields {
112 // This doesn't do the right thing for embedded type
113 // aliases where we should print the alias name, not
114 // the aliased type (see issue #44410).
120 if tag := t.Tag(i); tag != "" {
138 // Unions only appear as (syntactic) embedded elements
139 // in interfaces and syntactically cannot be empty.
143 for i, t := range t.terms {
154 w.string("interface{")
156 for _, m := range t.methods {
162 w.signature(m.typ.(*Signature))
164 for _, typ := range t.embeddeds {
185 // chan (<-chan T) requires parentheses
186 if c, _ := t.elem.(*Chan); c != nil && c.dir == RecvOnly {
206 if t.instPos != nil {
207 w.byte(instanceMarker)
212 w.typeList(t.targs.list())
213 } else if t.TParams().Len() != 0 {
214 // parameterized type
215 w.tParamList(t.TParams().list())
221 // Optionally write out package for typeparams (like Named).
222 // TODO(danscales): this is required for import/export, so
223 // we maybe need a separate function that won't be changed
224 // for debugging purposes.
225 if t.obj.pkg != nil {
226 writePackage(w.buf, t.obj.pkg, w.qf)
230 w.string(s + subscript(t.id))
236 // For externally defined implementations of Type.
237 // Note: In this case cycles won't be caught.
242 func (w *typeWriter) typeList(list []Type) {
244 for i, typ := range list {
253 func (w *typeWriter) tParamList(list []*TypeParam) {
256 for i, tpar := range list {
257 // Determine the type parameter and its constraint.
258 // list is expected to hold type parameter names,
259 // but don't crash if that's not the case.
262 bound = tpar.bound // should not be nil but we want to see it if it is
267 // bound changed - write previous one before advancing
278 w.string(tpar.obj.name)
288 func (w *typeWriter) typeName(obj *TypeName) {
290 assert(instanceHashing == 0) // we need an object for instance hashing
291 w.string("<Named w/o object>")
295 writePackage(w.buf, obj.pkg, w.qf)
299 if instanceHashing != 0 {
300 // For local defined types, use the (original!) TypeName's scope
301 // numbers to disambiguate.
302 typ := obj.typ.(*Named)
303 // TODO(gri) Figure out why typ.orig != typ.orig.orig sometimes
304 // and whether the loop can iterate more than twice.
305 // (It seems somehow connected to instance types.)
306 for typ.orig != typ {
309 w.writeScopeNumbers(typ.obj.parent)
313 // writeScopeNumbers writes the number sequence for this scope to buf
314 // in the form ".i.j.k" where i, j, k, etc. stand for scope numbers.
315 // If a scope is nil or has no parent (such as a package scope), nothing
317 func (w *typeWriter) writeScopeNumbers(s *Scope) {
318 if s != nil && s.number > 0 {
319 w.writeScopeNumbers(s.parent)
320 w.writef(".%d", s.number)
324 func (w *typeWriter) tuple(tup *Tuple, variadic bool) {
327 for i, v := range tup.vars {
336 if variadic && i == len(tup.vars)-1 {
337 if s, ok := typ.(*Slice); ok {
342 // append(s, "foo"...) leads to signature func([]byte, string...)
343 if t := asBasic(typ); t == nil || t.kind != String {
344 panic("expected string type")
357 // WriteSignature writes the representation of the signature sig to buf,
358 // without a leading "func" keyword.
359 // The Qualifier controls the printing of
360 // package-level objects, and may be nil.
361 func WriteSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier) {
362 newTypeWriter(buf, qf).signature(sig)
365 func (w *typeWriter) signature(sig *Signature) {
366 if sig.TParams().Len() != 0 {
367 w.tParamList(sig.TParams().list())
370 w.tuple(sig.params, sig.variadic)
372 n := sig.results.Len()
379 if n == 1 && sig.results.vars[0].name == "" {
380 // single unnamed result
381 w.typ(sig.results.vars[0].typ)
385 // multiple or named result(s)
386 w.tuple(sig.results, false)
389 // subscript returns the decimal (utf8) representation of x using subscript digits.
390 func subscript(x uint64) string {
391 const w = len("₀") // all digits 0...9 have the same utf8 width
396 utf8.EncodeRune(buf[i:], '₀'+rune(x%10)) // '₀' == U+2080
402 return string(buf[i:])