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 writeType(buf, typ, qf, make([]Type, 0, 8))
58 // instanceMarker is the prefix for an instantiated type
59 // in "non-evaluated" instance form.
60 const instanceMarker = '#'
62 func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) {
63 // Theoretically, this is a quadratic lookup algorithm, but in
64 // practice deeply nested composite types with unnamed component
65 // types are uncommon. This code is likely more efficient than
67 for _, t := range visited {
69 fmt.Fprintf(buf, "○%T", goTypeName(typ)) // cycle to typ
73 visited = append(visited, typ)
75 switch t := typ.(type) {
77 buf.WriteString("<nil>")
80 // exported basic types go into package unsafe
81 // (currently this is just unsafe.Pointer)
82 if isExported(t.name) {
83 if obj, _ := Unsafe.scope.Lookup(t.name).(*TypeName); obj != nil {
84 writeTypeName(buf, obj, qf)
88 buf.WriteString(t.name)
91 fmt.Fprintf(buf, "[%d]", t.len)
92 writeType(buf, t.elem, qf, visited)
96 writeType(buf, t.elem, qf, visited)
99 buf.WriteString("struct{")
100 for i, f := range t.fields {
102 buf.WriteString("; ")
104 // This doesn't do the right thing for embedded type
105 // aliases where we should print the alias name, not
106 // the aliased type (see issue #44410).
108 buf.WriteString(f.name)
111 writeType(buf, f.typ, qf, visited)
112 if tag := t.Tag(i); tag != "" {
113 fmt.Fprintf(buf, " %q", tag)
120 writeType(buf, t.base, qf, visited)
123 writeTuple(buf, t, false, qf, visited)
126 buf.WriteString("func")
127 writeSignature(buf, t, qf, visited)
130 // Unions only appear as (syntactic) embedded elements
131 // in interfaces and syntactically cannot be empty.
132 if t.NumTerms() == 0 {
133 panic("internal error: empty union")
135 for i, t := range t.terms {
142 writeType(buf, t.typ, qf, visited)
146 buf.WriteString("interface{")
148 for i, m := range t.methods {
150 buf.WriteString("; ")
152 buf.WriteString(m.name)
153 writeSignature(buf, m.typ.(*Signature), qf, visited)
156 if !empty && len(t.embeddeds) > 0 {
157 buf.WriteString("; ")
159 for i, typ := range t.embeddeds {
161 buf.WriteString("; ")
163 writeType(buf, typ, qf, visited)
166 // print /* incomplete */ if needed to satisfy existing tests
167 // TODO(gri) get rid of this eventually
168 if debug && t.tset == nil {
172 buf.WriteString("/* incomplete */")
177 buf.WriteString("map[")
178 writeType(buf, t.key, qf, visited)
180 writeType(buf, t.elem, qf, visited)
188 // chan (<-chan T) requires parentheses
189 if c, _ := t.elem.(*Chan); c != nil && c.dir == RecvOnly {
203 writeType(buf, t.elem, qf, visited)
209 if t.instance != nil {
210 buf.WriteByte(instanceMarker)
212 writeTypeName(buf, t.obj, qf)
216 writeTypeList(buf, t.targs, qf, visited)
218 } else if t.TParams().Len() != 0 {
219 // parameterized type
220 writeTParamList(buf, t.TParams().list(), qf, visited)
226 // Optionally write out package for typeparams (like Named).
227 // TODO(danscales): this is required for import/export, so
228 // we maybe need a separate function that won't be changed
229 // for debugging purposes.
230 if t.obj.pkg != nil {
231 writePackage(buf, t.obj.pkg, qf)
235 buf.WriteString(s + subscript(t.id))
241 // For externally defined implementations of Type.
242 // Note: In this case cycles won't be caught.
243 buf.WriteString(t.String())
247 func writeTypeList(buf *bytes.Buffer, list []Type, qf Qualifier, visited []Type) {
248 for i, typ := range list {
250 buf.WriteString(", ")
252 writeType(buf, typ, qf, visited)
256 func writeTParamList(buf *bytes.Buffer, list []*TypeName, qf Qualifier, visited []Type) {
259 for i, p := range list {
260 // TODO(gri) support 'any' sugar here.
261 var b Type = &emptyInterface
262 if t, _ := p.typ.(*TypeParam); t != nil && t.bound != nil {
267 // type bound changed - write previous one before advancing
269 writeType(buf, prev, qf, visited)
271 buf.WriteString(", ")
275 if t, _ := p.typ.(*TypeParam); t != nil {
276 writeType(buf, t, qf, visited)
278 buf.WriteString(p.name)
283 writeType(buf, prev, qf, visited)
288 func writeTypeName(buf *bytes.Buffer, obj *TypeName, qf Qualifier) {
290 buf.WriteString("<Named w/o object>")
294 writePackage(buf, obj.pkg, qf)
296 buf.WriteString(obj.name)
298 if instanceHashing != 0 {
299 // For local defined types, use the (original!) TypeName's scope
300 // numbers to disambiguate.
301 typ := obj.typ.(*Named)
302 // TODO(gri) Figure out why typ.orig != typ.orig.orig sometimes
303 // and whether the loop can iterate more than twice.
304 // (It seems somehow connected to instance types.)
305 for typ.orig != typ {
308 writeScopeNumbers(buf, typ.obj.parent)
312 // writeScopeNumbers writes the number sequence for this scope to buf
313 // in the form ".i.j.k" where i, j, k, etc. stand for scope numbers.
314 // If a scope is nil or has no parent (such as a package scope), nothing
316 func writeScopeNumbers(buf *bytes.Buffer, s *Scope) {
317 if s != nil && s.number > 0 {
318 writeScopeNumbers(buf, s.parent)
319 fmt.Fprintf(buf, ".%d", s.number)
323 func writeTuple(buf *bytes.Buffer, tup *Tuple, variadic bool, qf Qualifier, visited []Type) {
326 for i, v := range tup.vars {
328 buf.WriteString(", ")
331 buf.WriteString(v.name)
335 if variadic && i == len(tup.vars)-1 {
336 if s, ok := typ.(*Slice); ok {
337 buf.WriteString("...")
341 // append(s, "foo"...) leads to signature func([]byte, string...)
342 if t := asBasic(typ); t == nil || t.kind != String {
343 panic("internal error: string type expected")
345 writeType(buf, typ, qf, visited)
346 buf.WriteString("...")
350 writeType(buf, typ, qf, visited)
356 // WriteSignature writes the representation of the signature sig to buf,
357 // without a leading "func" keyword.
358 // The Qualifier controls the printing of
359 // package-level objects, and may be nil.
360 func WriteSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier) {
361 writeSignature(buf, sig, qf, make([]Type, 0, 8))
364 func writeSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier, visited []Type) {
365 if sig.TParams().Len() != 0 {
366 writeTParamList(buf, sig.TParams().list(), qf, visited)
369 writeTuple(buf, sig.params, sig.variadic, qf, visited)
371 n := sig.results.Len()
378 if n == 1 && sig.results.vars[0].name == "" {
379 // single unnamed result
380 writeType(buf, sig.results.vars[0].typ, qf, visited)
384 // multiple or named result(s)
385 writeTuple(buf, sig.results, false, qf, visited)
388 // subscript returns the decimal (utf8) representation of x using subscript digits.
389 func subscript(x uint64) string {
390 const w = len("₀") // all digits 0...9 have the same utf8 width
395 utf8.EncodeRune(buf[i:], '₀'+rune(x%10)) // '₀' == U+2080
401 return string(buf[i:])