]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/types2/typestring.go
all: remove trailing blank doc comment lines
[gostls13.git] / src / cmd / compile / internal / types2 / typestring.go
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.
4
5 // This file implements printing of types.
6
7 package types2
8
9 import (
10         "bytes"
11         "fmt"
12         "sort"
13         "strconv"
14         "strings"
15         "unicode/utf8"
16 )
17
18 // A Qualifier controls how named package-level objects are printed in
19 // calls to TypeString, ObjectString, and SelectionString.
20 //
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.
25 //
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
29
30 // RelativeTo returns a Qualifier that fully qualifies members of
31 // all packages other than pkg.
32 func RelativeTo(pkg *Package) Qualifier {
33         if pkg == nil {
34                 return nil
35         }
36         return func(other *Package) string {
37                 if pkg == other {
38                         return "" // same package; unqualified
39                 }
40                 return other.Path()
41         }
42 }
43
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)
49 }
50
51 func typeString(typ Type, qf Qualifier, debug bool) string {
52         var buf bytes.Buffer
53         w := newTypeWriter(&buf, qf)
54         w.debug = debug
55         w.typ(typ)
56         return buf.String()
57 }
58
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)
64 }
65
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)
72 }
73
74 type typeWriter struct {
75         buf     *bytes.Buffer
76         seen    map[Type]bool
77         qf      Qualifier
78         ctxt    *Context       // if non-nil, we are type hashing
79         tparams *TypeParamList // local type parameters
80         debug   bool           // if true, write debug annotations
81 }
82
83 func newTypeWriter(buf *bytes.Buffer, qf Qualifier) *typeWriter {
84         return &typeWriter{buf, make(map[Type]bool), qf, nil, nil, false}
85 }
86
87 func newTypeHasher(buf *bytes.Buffer, ctxt *Context) *typeWriter {
88         assert(ctxt != nil)
89         return &typeWriter{buf, make(map[Type]bool), nil, ctxt, nil, false}
90 }
91
92 func (w *typeWriter) byte(b byte) {
93         if w.ctxt != nil {
94                 if b == ' ' {
95                         b = '#'
96                 }
97                 w.buf.WriteByte(b)
98                 return
99         }
100         w.buf.WriteByte(b)
101         if b == ',' || b == ';' {
102                 w.buf.WriteByte(' ')
103         }
104 }
105
106 func (w *typeWriter) string(s string) {
107         w.buf.WriteString(s)
108 }
109
110 func (w *typeWriter) error(msg string) {
111         if w.ctxt != nil {
112                 panic(msg)
113         }
114         w.buf.WriteString("<" + msg + ">")
115 }
116
117 func (w *typeWriter) typ(typ Type) {
118         if w.seen[typ] {
119                 w.error("cycle to " + goTypeName(typ))
120                 return
121         }
122         w.seen[typ] = true
123         defer delete(w.seen, typ)
124
125         switch t := typ.(type) {
126         case nil:
127                 w.error("nil")
128
129         case *Basic:
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 {
134                                 w.typeName(obj)
135                                 break
136                         }
137                 }
138                 w.string(t.name)
139
140         case *Array:
141                 w.byte('[')
142                 w.string(strconv.FormatInt(t.len, 10))
143                 w.byte(']')
144                 w.typ(t.elem)
145
146         case *Slice:
147                 w.string("[]")
148                 w.typ(t.elem)
149
150         case *Struct:
151                 w.string("struct{")
152                 for i, f := range t.fields {
153                         if i > 0 {
154                                 w.byte(';')
155                         }
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).
159                         if !f.embedded {
160                                 w.string(f.name)
161                                 w.byte(' ')
162                         }
163                         w.typ(f.typ)
164                         if tag := t.Tag(i); tag != "" {
165                                 w.byte(' ')
166                                 // TODO(gri) If tag contains blanks, replacing them with '#'
167                                 //           in Context.TypeHash may produce another tag
168                                 //           accidentally.
169                                 w.string(strconv.Quote(tag))
170                         }
171                 }
172                 w.byte('}')
173
174         case *Pointer:
175                 w.byte('*')
176                 w.typ(t.base)
177
178         case *Tuple:
179                 w.tuple(t, false)
180
181         case *Signature:
182                 w.string("func")
183                 w.signature(t)
184
185         case *Union:
186                 // Unions only appear as (syntactic) embedded elements
187                 // in interfaces and syntactically cannot be empty.
188                 if t.Len() == 0 {
189                         w.error("empty union")
190                         break
191                 }
192                 for i, t := range t.terms {
193                         if i > 0 {
194                                 w.byte('|')
195                         }
196                         if t.tilde {
197                                 w.byte('~')
198                         }
199                         w.typ(t.typ)
200                 }
201
202         case *Interface:
203                 if w.ctxt == nil {
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.
208                                 w.string("any")
209                                 break
210                         }
211                         if t == universeComparable.Type().(*Named).underlying {
212                                 w.string("interface{comparable}")
213                                 break
214                         }
215                 }
216                 if t.implicit {
217                         if len(t.methods) == 0 && len(t.embeddeds) == 1 {
218                                 w.typ(t.embeddeds[0])
219                                 break
220                         }
221                         // Something's wrong with the implicit interface.
222                         // Print it as such and continue.
223                         w.string("/* implicit */ ")
224                 }
225                 w.string("interface{")
226                 first := true
227                 if w.ctxt != nil {
228                         w.typeSet(t.typeSet())
229                 } else {
230                         for _, m := range t.methods {
231                                 if !first {
232                                         w.byte(';')
233                                 }
234                                 first = false
235                                 w.string(m.name)
236                                 w.signature(m.typ.(*Signature))
237                         }
238                         for _, typ := range t.embeddeds {
239                                 if !first {
240                                         w.byte(';')
241                                 }
242                                 first = false
243                                 w.typ(typ)
244                         }
245                 }
246                 w.byte('}')
247
248         case *Map:
249                 w.string("map[")
250                 w.typ(t.key)
251                 w.byte(']')
252                 w.typ(t.elem)
253
254         case *Chan:
255                 var s string
256                 var parens bool
257                 switch t.dir {
258                 case SendRecv:
259                         s = "chan "
260                         // chan (<-chan T) requires parentheses
261                         if c, _ := t.elem.(*Chan); c != nil && c.dir == RecvOnly {
262                                 parens = true
263                         }
264                 case SendOnly:
265                         s = "chan<- "
266                 case RecvOnly:
267                         s = "<-chan "
268                 default:
269                         w.error("unknown channel direction")
270                 }
271                 w.string(s)
272                 if parens {
273                         w.byte('(')
274                 }
275                 w.typ(t.elem)
276                 if parens {
277                         w.byte(')')
278                 }
279
280         case *Named:
281                 // If hashing, write a unique prefix for t to represent its identity, since
282                 // named type identity is pointer identity.
283                 if w.ctxt != nil {
284                         w.string(strconv.Itoa(w.ctxt.getID(t)))
285                 }
286                 w.typeName(t.obj) // when hashing written for readability of the hash only
287                 if t.targs != nil {
288                         // instantiated type
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())
293                 }
294
295         case *TypeParam:
296                 if t.obj == nil {
297                         w.error("unnamed type parameter")
298                         break
299                 }
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))
305                 } else {
306                         w.string(t.obj.name)
307                         if w.debug || w.ctxt != nil {
308                                 w.string(subscript(t.id))
309                         }
310                 }
311
312         default:
313                 // For externally defined implementations of Type.
314                 // Note: In this case cycles won't be caught.
315                 w.string(t.String())
316         }
317 }
318
319 // typeSet writes a canonical hash for an interface type set.
320 func (w *typeWriter) typeSet(s *_TypeSet) {
321         assert(w.ctxt != nil)
322         first := true
323         for _, m := range s.methods {
324                 if !first {
325                         w.byte(';')
326                 }
327                 first = false
328                 w.string(m.name)
329                 w.signature(m.typ.(*Signature))
330         }
331         switch {
332         case s.terms.isAll():
333                 // nothing to do
334         case s.terms.isEmpty():
335                 w.string(s.terms.String())
336         default:
337                 var termHashes []string
338                 for _, term := range s.terms {
339                         // terms are not canonically sorted, so we sort their hashes instead.
340                         var buf bytes.Buffer
341                         if term.tilde {
342                                 buf.WriteByte('~')
343                         }
344                         newTypeHasher(&buf, w.ctxt).typ(term.typ)
345                         termHashes = append(termHashes, buf.String())
346                 }
347                 sort.Strings(termHashes)
348                 if !first {
349                         w.byte(';')
350                 }
351                 w.string(strings.Join(termHashes, "|"))
352         }
353 }
354
355 func (w *typeWriter) typeList(list []Type) {
356         w.byte('[')
357         for i, typ := range list {
358                 if i > 0 {
359                         w.byte(',')
360                 }
361                 w.typ(typ)
362         }
363         w.byte(']')
364 }
365
366 func (w *typeWriter) tParamList(list []*TypeParam) {
367         w.byte('[')
368         var prev Type
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.
373                 if tpar == nil {
374                         w.error("nil type parameter")
375                         continue
376                 }
377                 if i > 0 {
378                         if tpar.bound != prev {
379                                 // bound changed - write previous one before advancing
380                                 w.byte(' ')
381                                 w.typ(prev)
382                         }
383                         w.byte(',')
384                 }
385                 prev = tpar.bound
386                 w.typ(tpar)
387         }
388         if prev != nil {
389                 w.byte(' ')
390                 w.typ(prev)
391         }
392         w.byte(']')
393 }
394
395 func (w *typeWriter) typeName(obj *TypeName) {
396         if obj.pkg != nil {
397                 writePackage(w.buf, obj.pkg, w.qf)
398         }
399         w.string(obj.name)
400 }
401
402 func (w *typeWriter) tuple(tup *Tuple, variadic bool) {
403         w.byte('(')
404         if tup != nil {
405                 for i, v := range tup.vars {
406                         if i > 0 {
407                                 w.byte(',')
408                         }
409                         // parameter names are ignored for type identity and thus type hashes
410                         if w.ctxt == nil && v.name != "" {
411                                 w.string(v.name)
412                                 w.byte(' ')
413                         }
414                         typ := v.typ
415                         if variadic && i == len(tup.vars)-1 {
416                                 if s, ok := typ.(*Slice); ok {
417                                         w.string("...")
418                                         typ = s.elem
419                                 } else {
420                                         // special case:
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")
424                                                 continue
425                                         }
426                                         w.typ(typ)
427                                         w.string("...")
428                                         continue
429                                 }
430                         }
431                         w.typ(typ)
432                 }
433         }
434         w.byte(')')
435 }
436
437 func (w *typeWriter) signature(sig *Signature) {
438         if sig.TypeParams().Len() != 0 {
439                 if w.ctxt != nil {
440                         assert(w.tparams == nil)
441                         w.tparams = sig.TypeParams()
442                         defer func() {
443                                 w.tparams = nil
444                         }()
445                 }
446                 w.tParamList(sig.TypeParams().list())
447         }
448
449         w.tuple(sig.params, sig.variadic)
450
451         n := sig.results.Len()
452         if n == 0 {
453                 // no result
454                 return
455         }
456
457         w.byte(' ')
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)
461                 return
462         }
463
464         // multiple or named result(s)
465         w.tuple(sig.results, false)
466 }
467
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
471         var buf [32 * w]byte
472         i := len(buf)
473         for {
474                 i -= w
475                 utf8.EncodeRune(buf[i:], '₀'+rune(x%10)) // '₀' == U+2080
476                 x /= 10
477                 if x == 0 {
478                         break
479                 }
480         }
481         return string(buf[i:])
482 }