2 // Copyright 2013 The Go Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style
4 // license that can be found in the LICENSE file.
6 // This file implements printing of types.
16 // A Qualifier controls how named package-level objects are printed in
17 // calls to TypeString, ObjectString, and SelectionString.
19 // These three formatting routines call the Qualifier for each
20 // package-level object O, and if the Qualifier returns a non-empty
21 // string p, the object is printed in the form p.O.
22 // If it returns an empty string, only the object name O is printed.
24 // Using a nil Qualifier is equivalent to using (*Package).Path: the
25 // object is qualified by the import path, e.g., "encoding/json.Marshal".
27 type Qualifier func(*Package) string
29 // RelativeTo returns a Qualifier that fully qualifies members of
30 // all packages other than pkg.
31 func RelativeTo(pkg *Package) Qualifier {
35 return func(other *Package) string {
37 return "" // same package; unqualified
43 // If gcCompatibilityMode is set, printing of types is modified
44 // to match the representation of some types in the gc compiler:
46 // - byte and rune lose their alias name and simply stand for
47 // uint8 and int32 respectively
48 // - embedded interfaces get flattened (the embedding info is lost,
49 // and certain recursive interface types cannot be printed anymore)
51 // This makes it easier to compare packages computed with the type-
52 // checker vs packages imported from gc export data.
54 // Caution: This flag affects all uses of WriteType, globally.
55 // It is only provided for testing in conjunction with
58 // This flag is exported in the x/tools/go/types package. We don't
59 // need it at the moment in the std repo and so we don't export it
60 // anymore. We should eventually try to remove it altogether.
61 // TODO(gri) remove this
62 var gcCompatibilityMode bool
64 // TypeString returns the string representation of typ.
65 // The Qualifier controls the printing of
66 // package-level objects, and may be nil.
67 func TypeString(typ Type, qf Qualifier) string {
69 WriteType(&buf, typ, qf)
73 // WriteType writes the string representation of typ to buf.
74 // The Qualifier controls the printing of
75 // package-level objects, and may be nil.
76 func WriteType(buf *bytes.Buffer, typ Type, qf Qualifier) {
77 writeType(buf, typ, qf, make([]Type, 0, 8))
80 // instanceMarker is the prefix for an instantiated type
81 // in "non-evaluated" instance form.
82 const instanceMarker = '#'
84 func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) {
85 // Theoretically, this is a quadratic lookup algorithm, but in
86 // practice deeply nested composite types with unnamed component
87 // types are uncommon. This code is likely more efficient than
89 for _, t := range visited {
91 fmt.Fprintf(buf, "○%T", goTypeName(typ)) // cycle to typ
95 visited = append(visited, typ)
97 switch t := typ.(type) {
99 buf.WriteString("<nil>")
102 if t.kind == UnsafePointer {
103 buf.WriteString("unsafe.")
105 if gcCompatibilityMode {
106 // forget the alias names
114 buf.WriteString(t.name)
117 fmt.Fprintf(buf, "[%d]", t.len)
118 writeType(buf, t.elem, qf, visited)
121 buf.WriteString("[]")
122 writeType(buf, t.elem, qf, visited)
125 buf.WriteString("struct{")
126 for i, f := range t.fields {
128 buf.WriteString("; ")
130 buf.WriteString(f.name)
132 // emphasize that the embedded field's name
133 // doesn't match the field's type name
134 if f.name != embeddedFieldName(f.typ) {
135 buf.WriteString(" /* = ")
136 writeType(buf, f.typ, qf, visited)
137 buf.WriteString(" */")
141 writeType(buf, f.typ, qf, visited)
143 if tag := t.Tag(i); tag != "" {
144 fmt.Fprintf(buf, " %q", tag)
151 writeType(buf, t.base, qf, visited)
154 writeTuple(buf, t, false, qf, visited)
157 buf.WriteString("func")
158 writeSignature(buf, t, qf, visited)
161 for i, t := range t.types {
163 buf.WriteString(", ")
165 writeType(buf, t, qf, visited)
169 // We write the source-level methods and embedded types rather
170 // than the actual method set since resolved method signatures
171 // may have non-printable cycles if parameters have embedded
172 // interface types that (directly or indirectly) embed the
173 // current interface. For instance, consider the result type
177 // m() interface{ T }
180 buf.WriteString("interface{")
182 if gcCompatibilityMode {
183 // print flattened interface
184 // (useful to compare against gc-generated interfaces)
185 for i, m := range t.allMethods {
187 buf.WriteString("; ")
189 buf.WriteString(m.name)
190 writeSignature(buf, m.typ.(*Signature), qf, visited)
193 if !empty && t.allTypes != nil {
194 buf.WriteString("; ")
196 if t.allTypes != nil {
197 buf.WriteString("type ")
198 writeType(buf, t.allTypes, qf, visited)
201 // print explicit interface methods and embedded types
202 for i, m := range t.methods {
204 buf.WriteString("; ")
206 buf.WriteString(m.name)
207 writeSignature(buf, m.typ.(*Signature), qf, visited)
210 if !empty && t.types != nil {
211 buf.WriteString("; ")
214 buf.WriteString("type ")
215 writeType(buf, t.types, qf, visited)
218 if !empty && len(t.embeddeds) > 0 {
219 buf.WriteString("; ")
221 for i, typ := range t.embeddeds {
223 buf.WriteString("; ")
225 writeType(buf, typ, qf, visited)
229 if t.allMethods == nil || len(t.methods) > len(t.allMethods) {
233 buf.WriteString("/* incomplete */")
238 buf.WriteString("map[")
239 writeType(buf, t.key, qf, visited)
241 writeType(buf, t.elem, qf, visited)
249 // chan (<-chan T) requires parentheses
250 if c, _ := t.elem.(*Chan); c != nil && c.dir == RecvOnly {
264 writeType(buf, t.elem, qf, visited)
270 writeTypeName(buf, t.obj, qf)
274 writeTypeList(buf, t.targs, qf, visited)
276 } else if t.tparams != nil {
277 // parameterized type
278 writeTParamList(buf, t.tparams, qf, visited)
286 buf.WriteString(s + subscript(t.id))
289 buf.WriteByte(instanceMarker) // indicate "non-evaluated" syntactic instance
290 writeTypeName(buf, t.base.obj, qf)
292 writeTypeList(buf, t.targs, qf, visited)
302 // For externally defined implementations of Type.
303 buf.WriteString(t.String())
307 func writeTypeList(buf *bytes.Buffer, list []Type, qf Qualifier, visited []Type) {
308 for i, typ := range list {
310 buf.WriteString(", ")
312 writeType(buf, typ, qf, visited)
316 func writeTParamList(buf *bytes.Buffer, list []*TypeName, qf Qualifier, visited []Type) {
317 // bound returns the type bound for tname. The result is never nil.
318 bound := func(tname *TypeName) Type {
319 // be careful to avoid crashes in case of inconsistencies
320 if t, _ := tname.typ.(*TypeParam); t != nil && t.bound != nil {
323 return &emptyInterface
326 // If a single type bound is not the empty interface, we have to write them all.
328 for _, p := range list {
329 // bound(p) should be an interface but be careful (it may be invalid)
330 b := asInterface(bound(p))
331 if b != nil && !b.Empty() {
336 writeBounds = true // always write the bounds for new type parameter list syntax
340 for i, p := range list {
343 if writeBounds && b != prev {
344 // type bound changed - write previous one before advancing
346 writeType(buf, prev, qf, visited)
348 buf.WriteString(", ")
352 if t, _ := p.typ.(*TypeParam); t != nil {
353 writeType(buf, t, qf, visited)
355 buf.WriteString(p.name)
358 if writeBounds && prev != nil {
360 writeType(buf, prev, qf, visited)
365 func writeTypeName(buf *bytes.Buffer, obj *TypeName, qf Qualifier) {
366 s := "<Named w/o object>"
369 writePackage(buf, obj.pkg, qf)
371 // TODO(gri): function-local named types should be displayed
372 // differently from named types at package level to avoid
379 func writeTuple(buf *bytes.Buffer, tup *Tuple, variadic bool, qf Qualifier, visited []Type) {
382 for i, v := range tup.vars {
384 buf.WriteString(", ")
387 buf.WriteString(v.name)
391 if variadic && i == len(tup.vars)-1 {
392 if s, ok := typ.(*Slice); ok {
393 buf.WriteString("...")
397 // append(s, "foo"...) leads to signature func([]byte, string...)
398 if t := asBasic(typ); t == nil || t.kind != String {
399 panic("internal error: string type expected")
401 writeType(buf, typ, qf, visited)
402 buf.WriteString("...")
406 writeType(buf, typ, qf, visited)
412 // WriteSignature writes the representation of the signature sig to buf,
413 // without a leading "func" keyword.
414 // The Qualifier controls the printing of
415 // package-level objects, and may be nil.
416 func WriteSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier) {
417 writeSignature(buf, sig, qf, make([]Type, 0, 8))
420 func writeSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier, visited []Type) {
421 if sig.tparams != nil {
422 writeTParamList(buf, sig.tparams, qf, visited)
425 writeTuple(buf, sig.params, sig.variadic, qf, visited)
427 n := sig.results.Len()
434 if n == 1 && sig.results.vars[0].name == "" {
435 // single unnamed result
436 writeType(buf, sig.results.vars[0].typ, qf, visited)
440 // multiple or named result(s)
441 writeTuple(buf, sig.results, false, qf, visited)
444 // embeddedFieldName returns an embedded field's name given its type.
445 // The result is "" if the type doesn't have an embedded field name.
446 func embeddedFieldName(typ Type) string {
447 switch t := typ.(type) {
453 // *T is ok, but **T is not
454 if _, ok := t.base.(*Pointer); !ok {
455 return embeddedFieldName(t.base)
458 return t.base.obj.name
460 return "" // not a (pointer to) a defined type
463 // subscript returns the decimal (utf8) representation of x using subscript digits.
464 func subscript(x uint64) string {
465 const w = len("₀") // all digits 0...9 have the same utf8 width
470 utf8.EncodeRune(buf[i:], '₀'+rune(x%10)) // '₀' == U+2080
476 return string(buf[i:])