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 {
46 return typeString(typ, qf, false)
49 func typeString(typ Type, qf Qualifier, debug bool) string {
51 w := newTypeWriter(&buf, qf)
57 // WriteType writes the string representation of typ to buf.
58 // The Qualifier controls the printing of
59 // package-level objects, and may be nil.
60 func WriteType(buf *bytes.Buffer, typ Type, qf Qualifier) {
61 newTypeWriter(buf, qf).typ(typ)
64 // WriteSignature writes the representation of the signature sig to buf,
65 // without a leading "func" keyword.
66 // The Qualifier controls the printing of
67 // package-level objects, and may be nil.
68 func WriteSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier) {
69 newTypeWriter(buf, qf).signature(sig)
72 type typeWriter struct {
76 ctxt *Context // if non-nil, we are type hashing
77 debug bool // if true, write debug annotations
80 func newTypeWriter(buf *bytes.Buffer, qf Qualifier) *typeWriter {
81 return &typeWriter{buf, make(map[Type]bool), qf, nil, false}
84 func newTypeHasher(buf *bytes.Buffer, ctxt *Context) *typeWriter {
86 return &typeWriter{buf, make(map[Type]bool), nil, ctxt, false}
89 func (w *typeWriter) byte(b byte) {
98 if b == ',' || b == ';' {
103 func (w *typeWriter) string(s string) {
107 func (w *typeWriter) error(msg string) {
111 w.buf.WriteString("<" + msg + ">")
114 func (w *typeWriter) typ(typ Type) {
116 w.error("cycle to " + goTypeName(typ))
120 defer delete(w.seen, typ)
122 switch t := typ.(type) {
127 // exported basic types go into package unsafe
128 // (currently this is just unsafe.Pointer)
129 if isExported(t.name) {
130 if obj, _ := Unsafe.scope.Lookup(t.name).(*TypeName); obj != nil {
139 w.string(strconv.FormatInt(t.len, 10))
149 for i, f := range t.fields {
153 // This doesn't do the right thing for embedded type
154 // aliases where we should print the alias name, not
155 // the aliased type (see issue #44410).
161 if tag := t.Tag(i); tag != "" {
163 // TODO(gri) If tag contains blanks, replacing them with '#'
164 // in Context.TypeHash may produce another tag
166 w.string(strconv.Quote(tag))
183 // Unions only appear as (syntactic) embedded elements
184 // in interfaces and syntactically cannot be empty.
186 w.error("empty union")
189 for i, t := range t.terms {
201 if len(t.methods) == 0 && len(t.embeddeds) == 1 {
202 w.typ(t.embeddeds[0])
205 // Something's wrong with the implicit interface.
206 // Print it as such and continue.
207 w.string("/* implicit */ ")
209 w.string("interface{")
211 for _, m := range t.methods {
217 w.signature(m.typ.(*Signature))
219 for _, typ := range t.embeddeds {
240 // chan (<-chan T) requires parentheses
241 if c, _ := t.elem.(*Chan); c != nil && c.dir == RecvOnly {
249 w.error("unknown channel direction")
265 w.typeList(t.targs.list())
266 } else if w.ctxt == nil && t.TypeParams().Len() != 0 { // For type hashing, don't need to format the TParams
267 // parameterized type
268 w.tParamList(t.TypeParams().list())
273 w.error("unnamed type parameter")
276 // Optionally write out package for typeparams (like Named).
277 if t.obj.pkg != nil {
278 writePackage(w.buf, t.obj.pkg, w.qf)
281 if w.debug || w.ctxt != nil {
282 w.string(subscript(t.id))
286 // For externally defined implementations of Type.
287 // Note: In this case cycles won't be caught.
292 // If w.ctxt is non-nil, typePrefix writes a unique prefix for the named type t
293 // based on the types already observed by w.ctxt. If w.ctxt is nil, it does
295 func (w *typeWriter) typePrefix(t *Named) {
297 w.string(strconv.Itoa(w.ctxt.idForType(t)))
301 func (w *typeWriter) typeList(list []Type) {
303 for i, typ := range list {
312 func (w *typeWriter) tParamList(list []*TypeParam) {
315 for i, tpar := range list {
316 // Determine the type parameter and its constraint.
317 // list is expected to hold type parameter names,
318 // but don't crash if that's not the case.
320 w.error("nil type parameter")
324 if tpar.bound != prev {
325 // bound changed - write previous one before advancing
341 func (w *typeWriter) typeName(obj *TypeName) {
343 writePackage(w.buf, obj.pkg, w.qf)
348 func (w *typeWriter) tuple(tup *Tuple, variadic bool) {
351 for i, v := range tup.vars {
355 // parameter names are ignored for type identity and thus type hashes
356 if w.ctxt == nil && v.name != "" {
361 if variadic && i == len(tup.vars)-1 {
362 if s, ok := typ.(*Slice); ok {
367 // append(s, "foo"...) leads to signature func([]byte, string...)
368 if t := asBasic(typ); t == nil || t.kind != String {
369 w.error("expected string type")
383 func (w *typeWriter) signature(sig *Signature) {
384 if sig.TypeParams().Len() != 0 {
385 w.tParamList(sig.TypeParams().list())
388 w.tuple(sig.params, sig.variadic)
390 n := sig.results.Len()
397 if n == 1 && (w.ctxt != nil || sig.results.vars[0].name == "") {
398 // single unnamed result (if type hashing, name must be ignored)
399 w.typ(sig.results.vars[0].typ)
403 // multiple or named result(s)
404 w.tuple(sig.results, false)
407 // subscript returns the decimal (utf8) representation of x using subscript digits.
408 func subscript(x uint64) string {
409 const w = len("₀") // all digits 0...9 have the same utf8 width
414 utf8.EncodeRune(buf[i:], '₀'+rune(x%10)) // '₀' == U+2080
420 return string(buf[i:])