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.
18 // A Qualifier controls how named package-level objects are printed in
19 // calls to TypeString, ObjectString, and SelectionString.
21 // These three formatting routines call the Qualifier for each
22 // package-level object O, and if the Qualifier returns a non-empty
23 // string p, the object is printed in the form p.O.
24 // If it returns an empty string, only the object name O is printed.
26 // Using a nil Qualifier is equivalent to using (*Package).Path: the
27 // object is qualified by the import path, e.g., "encoding/json.Marshal".
28 type Qualifier func(*Package) string
30 // RelativeTo returns a Qualifier that fully qualifies members of
31 // all packages other than pkg.
32 func RelativeTo(pkg *Package) Qualifier {
36 return func(other *Package) string {
38 return "" // same package; unqualified
44 // TypeString returns the string representation of typ.
45 // The Qualifier controls the printing of
46 // package-level objects, and may be nil.
47 func TypeString(typ Type, qf Qualifier) string {
48 return typeString(typ, qf, false)
51 func typeString(typ Type, qf Qualifier, debug bool) string {
53 w := newTypeWriter(&buf, qf)
59 // WriteType writes the string representation of typ to buf.
60 // The Qualifier controls the printing of
61 // package-level objects, and may be nil.
62 func WriteType(buf *bytes.Buffer, typ Type, qf Qualifier) {
63 newTypeWriter(buf, qf).typ(typ)
66 // WriteSignature writes the representation of the signature sig to buf,
67 // without a leading "func" keyword.
68 // The Qualifier controls the printing of
69 // package-level objects, and may be nil.
70 func WriteSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier) {
71 newTypeWriter(buf, qf).signature(sig)
74 type typeWriter struct {
78 ctxt *Context // if non-nil, we are type hashing
79 tparams *TypeParamList // local type parameters
80 debug bool // if true, write debug annotations
83 func newTypeWriter(buf *bytes.Buffer, qf Qualifier) *typeWriter {
84 return &typeWriter{buf, make(map[Type]bool), qf, nil, nil, false}
87 func newTypeHasher(buf *bytes.Buffer, ctxt *Context) *typeWriter {
89 return &typeWriter{buf, make(map[Type]bool), nil, ctxt, nil, false}
92 func (w *typeWriter) byte(b byte) {
101 if b == ',' || b == ';' {
106 func (w *typeWriter) string(s string) {
110 func (w *typeWriter) error(msg string) {
114 w.buf.WriteString("<" + msg + ">")
117 func (w *typeWriter) typ(typ Type) {
119 w.error("cycle to " + goTypeName(typ))
123 defer delete(w.seen, typ)
125 switch t := typ.(type) {
130 // exported basic types go into package unsafe
131 // (currently this is just unsafe.Pointer)
132 if isExported(t.name) {
133 if obj, _ := Unsafe.scope.Lookup(t.name).(*TypeName); obj != nil {
142 w.string(strconv.FormatInt(t.len, 10))
152 for i, f := range t.fields {
156 // This doesn't do the right thing for embedded type
157 // aliases where we should print the alias name, not
158 // the aliased type (see issue #44410).
164 if tag := t.Tag(i); tag != "" {
166 // TODO(gri) If tag contains blanks, replacing them with '#'
167 // in Context.TypeHash may produce another tag
169 w.string(strconv.Quote(tag))
186 // Unions only appear as (syntactic) embedded elements
187 // in interfaces and syntactically cannot be empty.
189 w.error("empty union")
192 for i, t := range t.terms {
204 if t == universeAny.Type() {
205 // When not hashing, we can try to improve type strings by writing "any"
206 // for a type that is pointer-identical to universeAny. This logic should
207 // be deprecated by more robust handling for aliases.
211 if t == universeComparable.Type().(*Named).underlying {
212 w.string("interface{comparable}")
217 if len(t.methods) == 0 && len(t.embeddeds) == 1 {
218 w.typ(t.embeddeds[0])
221 // Something's wrong with the implicit interface.
222 // Print it as such and continue.
223 w.string("/* implicit */ ")
225 w.string("interface{")
228 w.typeSet(t.typeSet())
230 for _, m := range t.methods {
236 w.signature(m.typ.(*Signature))
238 for _, typ := range t.embeddeds {
260 // chan (<-chan T) requires parentheses
261 if c, _ := t.elem.(*Chan); c != nil && c.dir == RecvOnly {
269 w.error("unknown channel direction")
281 // If hashing, write a unique prefix for t to represent its identity, since
282 // named type identity is pointer identity.
284 w.string(strconv.Itoa(w.ctxt.getID(t)))
286 w.typeName(t.obj) // when hashing written for readability of the hash only
289 w.typeList(t.targs.list())
290 } else if w.ctxt == nil && t.TypeParams().Len() != 0 { // For type hashing, don't need to format the TypeParams
291 // parameterized type
292 w.tParamList(t.TypeParams().list())
297 w.error("unnamed type parameter")
300 if i := tparamIndex(w.tparams.list(), t); i >= 0 {
301 // The names of type parameters that are declared by the type being
302 // hashed are not part of the type identity. Replace them with a
303 // placeholder indicating their index.
304 w.string(fmt.Sprintf("$%d", i))
307 if w.debug || w.ctxt != nil {
308 w.string(subscript(t.id))
313 // For externally defined implementations of Type.
314 // Note: In this case cycles won't be caught.
319 // typeSet writes a canonical hash for an interface type set.
320 func (w *typeWriter) typeSet(s *_TypeSet) {
321 assert(w.ctxt != nil)
323 for _, m := range s.methods {
329 w.signature(m.typ.(*Signature))
332 case s.terms.isAll():
334 case s.terms.isEmpty():
335 w.string(s.terms.String())
337 var termHashes []string
338 for _, term := range s.terms {
339 // terms are not canonically sorted, so we sort their hashes instead.
344 newTypeHasher(&buf, w.ctxt).typ(term.typ)
345 termHashes = append(termHashes, buf.String())
347 sort.Strings(termHashes)
351 w.string(strings.Join(termHashes, "|"))
355 func (w *typeWriter) typeList(list []Type) {
357 for i, typ := range list {
366 func (w *typeWriter) tParamList(list []*TypeParam) {
369 for i, tpar := range list {
370 // Determine the type parameter and its constraint.
371 // list is expected to hold type parameter names,
372 // but don't crash if that's not the case.
374 w.error("nil type parameter")
378 if tpar.bound != prev {
379 // bound changed - write previous one before advancing
395 func (w *typeWriter) typeName(obj *TypeName) {
397 writePackage(w.buf, obj.pkg, w.qf)
402 func (w *typeWriter) tuple(tup *Tuple, variadic bool) {
405 for i, v := range tup.vars {
409 // parameter names are ignored for type identity and thus type hashes
410 if w.ctxt == nil && v.name != "" {
415 if variadic && i == len(tup.vars)-1 {
416 if s, ok := typ.(*Slice); ok {
421 // append(s, "foo"...) leads to signature func([]byte, string...)
422 if t, _ := under(typ).(*Basic); t == nil || t.kind != String {
423 w.error("expected string type")
437 func (w *typeWriter) signature(sig *Signature) {
438 if sig.TypeParams().Len() != 0 {
440 assert(w.tparams == nil)
441 w.tparams = sig.TypeParams()
446 w.tParamList(sig.TypeParams().list())
449 w.tuple(sig.params, sig.variadic)
451 n := sig.results.Len()
458 if n == 1 && (w.ctxt != nil || sig.results.vars[0].name == "") {
459 // single unnamed result (if type hashing, name must be ignored)
460 w.typ(sig.results.vars[0].typ)
464 // multiple or named result(s)
465 w.tuple(sig.results, false)
468 // subscript returns the decimal (utf8) representation of x using subscript digits.
469 func subscript(x uint64) string {
470 const w = len("₀") // all digits 0...9 have the same utf8 width
475 utf8.EncodeRune(buf[i:], '₀'+rune(x%10)) // '₀' == U+2080
481 return string(buf[i:])