]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/types2/typestring.go
cmd/compile/internal/types2: remove subscripts from type parameter names
[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         "strconv"
12         "unicode/utf8"
13 )
14
15 // A Qualifier controls how named package-level objects are printed in
16 // calls to TypeString, ObjectString, and SelectionString.
17 //
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.
22 //
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".
25 //
26 type Qualifier func(*Package) string
27
28 // RelativeTo returns a Qualifier that fully qualifies members of
29 // all packages other than pkg.
30 func RelativeTo(pkg *Package) Qualifier {
31         if pkg == nil {
32                 return nil
33         }
34         return func(other *Package) string {
35                 if pkg == other {
36                         return "" // same package; unqualified
37                 }
38                 return other.Path()
39         }
40 }
41
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)
47 }
48
49 func typeString(typ Type, qf Qualifier, debug bool) string {
50         var buf bytes.Buffer
51         w := newTypeWriter(&buf, qf)
52         w.debug = debug
53         w.typ(typ)
54         return buf.String()
55 }
56
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)
62 }
63
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)
70 }
71
72 type typeWriter struct {
73         buf   *bytes.Buffer
74         seen  map[Type]bool
75         qf    Qualifier
76         ctxt  *Context // if non-nil, we are type hashing
77         debug bool     // if true, write debug annotations
78 }
79
80 func newTypeWriter(buf *bytes.Buffer, qf Qualifier) *typeWriter {
81         return &typeWriter{buf, make(map[Type]bool), qf, nil, false}
82 }
83
84 func newTypeHasher(buf *bytes.Buffer, ctxt *Context) *typeWriter {
85         assert(ctxt != nil)
86         return &typeWriter{buf, make(map[Type]bool), nil, ctxt, false}
87 }
88
89 func (w *typeWriter) byte(b byte) {
90         if w.ctxt != nil {
91                 if b == ' ' {
92                         b = '#'
93                 }
94                 w.buf.WriteByte(b)
95                 return
96         }
97         w.buf.WriteByte(b)
98         if b == ',' || b == ';' {
99                 w.buf.WriteByte(' ')
100         }
101 }
102
103 func (w *typeWriter) string(s string) {
104         w.buf.WriteString(s)
105 }
106
107 func (w *typeWriter) error(msg string) {
108         if w.ctxt != nil {
109                 panic(msg)
110         }
111         w.buf.WriteString("<" + msg + ">")
112 }
113
114 func (w *typeWriter) typ(typ Type) {
115         if w.seen[typ] {
116                 w.error("cycle to " + goTypeName(typ))
117                 return
118         }
119         w.seen[typ] = true
120         defer delete(w.seen, typ)
121
122         switch t := typ.(type) {
123         case nil:
124                 w.error("nil")
125
126         case *Basic:
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 {
131                                 w.typeName(obj)
132                                 break
133                         }
134                 }
135                 w.string(t.name)
136
137         case *Array:
138                 w.byte('[')
139                 w.string(strconv.FormatInt(t.len, 10))
140                 w.byte(']')
141                 w.typ(t.elem)
142
143         case *Slice:
144                 w.string("[]")
145                 w.typ(t.elem)
146
147         case *Struct:
148                 w.string("struct{")
149                 for i, f := range t.fields {
150                         if i > 0 {
151                                 w.byte(';')
152                         }
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).
156                         if !f.embedded {
157                                 w.string(f.name)
158                                 w.byte(' ')
159                         }
160                         w.typ(f.typ)
161                         if tag := t.Tag(i); tag != "" {
162                                 w.byte(' ')
163                                 // TODO(gri) If tag contains blanks, replacing them with '#'
164                                 //           in Context.TypeHash may produce another tag
165                                 //           accidentally.
166                                 w.string(strconv.Quote(tag))
167                         }
168                 }
169                 w.byte('}')
170
171         case *Pointer:
172                 w.byte('*')
173                 w.typ(t.base)
174
175         case *Tuple:
176                 w.tuple(t, false)
177
178         case *Signature:
179                 w.string("func")
180                 w.signature(t)
181
182         case *Union:
183                 // Unions only appear as (syntactic) embedded elements
184                 // in interfaces and syntactically cannot be empty.
185                 if t.Len() == 0 {
186                         w.error("empty union")
187                         break
188                 }
189                 for i, t := range t.terms {
190                         if i > 0 {
191                                 w.byte('|')
192                         }
193                         if t.tilde {
194                                 w.byte('~')
195                         }
196                         w.typ(t.typ)
197                 }
198
199         case *Interface:
200                 if t.implicit {
201                         if len(t.methods) == 0 && len(t.embeddeds) == 1 {
202                                 w.typ(t.embeddeds[0])
203                                 break
204                         }
205                         // Something's wrong with the implicit interface.
206                         // Print it as such and continue.
207                         w.string("/* implicit */ ")
208                 }
209                 w.string("interface{")
210                 first := true
211                 for _, m := range t.methods {
212                         if !first {
213                                 w.byte(';')
214                         }
215                         first = false
216                         w.string(m.name)
217                         w.signature(m.typ.(*Signature))
218                 }
219                 for _, typ := range t.embeddeds {
220                         if !first {
221                                 w.byte(';')
222                         }
223                         first = false
224                         w.typ(typ)
225                 }
226                 w.byte('}')
227
228         case *Map:
229                 w.string("map[")
230                 w.typ(t.key)
231                 w.byte(']')
232                 w.typ(t.elem)
233
234         case *Chan:
235                 var s string
236                 var parens bool
237                 switch t.dir {
238                 case SendRecv:
239                         s = "chan "
240                         // chan (<-chan T) requires parentheses
241                         if c, _ := t.elem.(*Chan); c != nil && c.dir == RecvOnly {
242                                 parens = true
243                         }
244                 case SendOnly:
245                         s = "chan<- "
246                 case RecvOnly:
247                         s = "<-chan "
248                 default:
249                         w.error("unknown channel direction")
250                 }
251                 w.string(s)
252                 if parens {
253                         w.byte('(')
254                 }
255                 w.typ(t.elem)
256                 if parens {
257                         w.byte(')')
258                 }
259
260         case *Named:
261                 w.typePrefix(t)
262                 w.typeName(t.obj)
263                 if t.targs != nil {
264                         // instantiated type
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())
269                 }
270
271         case *TypeParam:
272                 if t.obj == nil {
273                         w.error("unnamed type parameter")
274                         break
275                 }
276                 // Optionally write out package for typeparams (like Named).
277                 if t.obj.pkg != nil {
278                         writePackage(w.buf, t.obj.pkg, w.qf)
279                 }
280                 w.string(t.obj.name)
281                 if w.debug || w.ctxt != nil {
282                         w.string(subscript(t.id))
283                 }
284
285         default:
286                 // For externally defined implementations of Type.
287                 // Note: In this case cycles won't be caught.
288                 w.string(t.String())
289         }
290 }
291
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
294 // nothing.
295 func (w *typeWriter) typePrefix(t *Named) {
296         if w.ctxt != nil {
297                 w.string(strconv.Itoa(w.ctxt.idForType(t)))
298         }
299 }
300
301 func (w *typeWriter) typeList(list []Type) {
302         w.byte('[')
303         for i, typ := range list {
304                 if i > 0 {
305                         w.byte(',')
306                 }
307                 w.typ(typ)
308         }
309         w.byte(']')
310 }
311
312 func (w *typeWriter) tParamList(list []*TypeParam) {
313         w.byte('[')
314         var prev Type
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.
319                 if tpar == nil {
320                         w.error("nil type parameter")
321                         continue
322                 }
323                 if i > 0 {
324                         if tpar.bound != prev {
325                                 // bound changed - write previous one before advancing
326                                 w.byte(' ')
327                                 w.typ(prev)
328                         }
329                         w.byte(',')
330                 }
331                 prev = tpar.bound
332                 w.typ(tpar)
333         }
334         if prev != nil {
335                 w.byte(' ')
336                 w.typ(prev)
337         }
338         w.byte(']')
339 }
340
341 func (w *typeWriter) typeName(obj *TypeName) {
342         if obj.pkg != nil {
343                 writePackage(w.buf, obj.pkg, w.qf)
344         }
345         w.string(obj.name)
346 }
347
348 func (w *typeWriter) tuple(tup *Tuple, variadic bool) {
349         w.byte('(')
350         if tup != nil {
351                 for i, v := range tup.vars {
352                         if i > 0 {
353                                 w.byte(',')
354                         }
355                         // parameter names are ignored for type identity and thus type hashes
356                         if w.ctxt == nil && v.name != "" {
357                                 w.string(v.name)
358                                 w.byte(' ')
359                         }
360                         typ := v.typ
361                         if variadic && i == len(tup.vars)-1 {
362                                 if s, ok := typ.(*Slice); ok {
363                                         w.string("...")
364                                         typ = s.elem
365                                 } else {
366                                         // special case:
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")
370                                                 continue
371                                         }
372                                         w.typ(typ)
373                                         w.string("...")
374                                         continue
375                                 }
376                         }
377                         w.typ(typ)
378                 }
379         }
380         w.byte(')')
381 }
382
383 func (w *typeWriter) signature(sig *Signature) {
384         if sig.TypeParams().Len() != 0 {
385                 w.tParamList(sig.TypeParams().list())
386         }
387
388         w.tuple(sig.params, sig.variadic)
389
390         n := sig.results.Len()
391         if n == 0 {
392                 // no result
393                 return
394         }
395
396         w.byte(' ')
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)
400                 return
401         }
402
403         // multiple or named result(s)
404         w.tuple(sig.results, false)
405 }
406
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
410         var buf [32 * w]byte
411         i := len(buf)
412         for {
413                 i -= w
414                 utf8.EncodeRune(buf[i:], '₀'+rune(x%10)) // '₀' == U+2080
415                 x /= 10
416                 if x == 0 {
417                         break
418                 }
419         }
420         return string(buf[i:])
421 }