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.
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 // TypeString returns the string representation of typ.
44 // The Qualifier controls the printing of
45 // package-level objects, and may be nil.
46 func TypeString(typ Type, qf Qualifier) string {
48 WriteType(&buf, typ, qf)
52 // WriteType writes the string representation of typ to buf.
53 // The Qualifier controls the printing of
54 // package-level objects, and may be nil.
55 func WriteType(buf *bytes.Buffer, typ Type, qf Qualifier) {
56 newTypeWriter(buf, qf).typ(typ)
59 // WriteSignature writes the representation of the signature sig to buf,
60 // without a leading "func" keyword.
61 // The Qualifier controls the printing of
62 // package-level objects, and may be nil.
63 func WriteSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier) {
64 newTypeWriter(buf, qf).signature(sig)
67 // instanceMarker is the prefix for an instantiated type in unexpanded form.
68 const instanceMarker = '#'
70 type typeWriter struct {
74 env *Environment // if non-nil, we are type hashing
77 func newTypeWriter(buf *bytes.Buffer, qf Qualifier) *typeWriter {
78 return &typeWriter{buf, make(map[Type]bool), qf, nil}
81 func newTypeHasher(buf *bytes.Buffer, env *Environment) *typeWriter {
83 return &typeWriter{buf, make(map[Type]bool), nil, env}
86 func (w *typeWriter) byte(b byte) { w.buf.WriteByte(b) }
87 func (w *typeWriter) string(s string) { w.buf.WriteString(s) }
88 func (w *typeWriter) writef(format string, args ...interface{}) { fmt.Fprintf(w.buf, format, args...) }
89 func (w *typeWriter) error(msg string) {
93 w.string("<" + msg + ">")
96 func (w *typeWriter) typ(typ Type) {
98 w.error("cycle to " + goTypeName(typ))
102 defer delete(w.seen, typ)
104 switch t := typ.(type) {
109 // exported basic types go into package unsafe
110 // (currently this is just unsafe.Pointer)
111 if isExported(t.name) {
112 if obj, _ := Unsafe.scope.Lookup(t.name).(*TypeName); obj != nil {
120 w.writef("[%d]", t.len)
129 for i, f := range t.fields {
133 // This doesn't do the right thing for embedded type
134 // aliases where we should print the alias name, not
135 // the aliased type (see issue #44410).
141 if tag := t.Tag(i); tag != "" {
159 // Unions only appear as (syntactic) embedded elements
160 // in interfaces and syntactically cannot be empty.
162 w.error("empty union")
165 for i, t := range t.terms {
176 w.string("interface{")
178 for _, m := range t.methods {
184 w.signature(m.typ.(*Signature))
186 for _, typ := range t.embeddeds {
207 // chan (<-chan T) requires parentheses
208 if c, _ := t.elem.(*Chan); c != nil && c.dir == RecvOnly {
216 w.error("unknown channel direction")
228 // Instance markers indicate unexpanded instantiated
229 // types. Write them to aid debugging, but don't write
230 // them when we need an instance hash: whether a type
231 // is fully expanded or not doesn't matter for identity.
232 if w.env == nil && t.instPos != nil {
233 w.byte(instanceMarker)
239 w.typeList(t.targs.list())
240 } else if w.env == nil && t.TParams().Len() != 0 { // For type hashing, don't need to format the TParams
241 // parameterized type
242 w.tParamList(t.TParams().list())
247 w.error("unnamed type parameter")
250 // Optionally write out package for typeparams (like Named).
251 // TODO(danscales): this is required for import/export, so
252 // we maybe need a separate function that won't be changed
253 // for debugging purposes.
254 if t.obj.pkg != nil {
255 writePackage(w.buf, t.obj.pkg, w.qf)
257 w.string(t.obj.name + subscript(t.id))
263 // For externally defined implementations of Type.
264 // Note: In this case cycles won't be caught.
269 // If w.env is non-nil, typePrefix writes a unique prefix for the named type t
270 // based on the types already observed by w.env. If w.env is nil, it does
272 func (w *typeWriter) typePrefix(t *Named) {
274 w.string(strconv.Itoa(w.env.idForType(t)))
278 func (w *typeWriter) typeList(list []Type) {
280 for i, typ := range list {
289 func (w *typeWriter) tParamList(list []*TypeParam) {
292 for i, tpar := range list {
293 // Determine the type parameter and its constraint.
294 // list is expected to hold type parameter names,
295 // but don't crash if that's not the case.
297 w.error("nil type parameter")
301 if tpar.bound != prev {
302 // bound changed - write previous one before advancing
318 func (w *typeWriter) typeName(obj *TypeName) {
320 writePackage(w.buf, obj.pkg, w.qf)
325 func (w *typeWriter) tuple(tup *Tuple, variadic bool) {
328 for i, v := range tup.vars {
332 // parameter names are ignored for type identity and thus type hashes
333 if w.env == nil && v.name != "" {
338 if variadic && i == len(tup.vars)-1 {
339 if s, ok := typ.(*Slice); ok {
344 // append(s, "foo"...) leads to signature func([]byte, string...)
345 if t := asBasic(typ); t == nil || t.kind != String {
346 w.error("expected string type")
360 func (w *typeWriter) signature(sig *Signature) {
361 if sig.TParams().Len() != 0 {
362 w.tParamList(sig.TParams().list())
365 w.tuple(sig.params, sig.variadic)
367 n := sig.results.Len()
374 if n == 1 && (w.env != nil || sig.results.vars[0].name == "") {
375 // single unnamed result (if type hashing, name must be ignored)
376 w.typ(sig.results.vars[0].typ)
380 // multiple or named result(s)
381 w.tuple(sig.results, false)
384 // subscript returns the decimal (utf8) representation of x using subscript digits.
385 func subscript(x uint64) string {
386 const w = len("₀") // all digits 0...9 have the same utf8 width
391 utf8.EncodeRune(buf[i:], '₀'+rune(x%10)) // '₀' == U+2080
397 return string(buf[i:])