]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/types2/typestring.go
cmd/compile/internal/types2: use a typeWriter to write types (cleanup)
[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         "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         var buf bytes.Buffer
47         WriteType(&buf, typ, qf)
48         return buf.String()
49 }
50
51 // WriteType writes the string representation of typ to buf.
52 // The Qualifier controls the printing of
53 // package-level objects, and may be nil.
54 func WriteType(buf *bytes.Buffer, typ Type, qf Qualifier) {
55         newTypeWriter(buf, qf).typ(typ)
56 }
57
58 // instanceMarker is the prefix for an instantiated type in unexpanded form.
59 const instanceMarker = '#'
60
61 type typeWriter struct {
62         buf  *bytes.Buffer
63         seen map[Type]bool
64         qf   Qualifier
65 }
66
67 func newTypeWriter(buf *bytes.Buffer, qf Qualifier) *typeWriter {
68         return &typeWriter{buf, make(map[Type]bool), qf}
69 }
70
71 func (w *typeWriter) byte(b byte)                               { w.buf.WriteByte(b) }
72 func (w *typeWriter) string(s string)                           { w.buf.WriteString(s) }
73 func (w *typeWriter) writef(format string, args ...interface{}) { fmt.Fprintf(w.buf, format, args...) }
74
75 func (w *typeWriter) typ(typ Type) {
76         if w.seen[typ] {
77                 w.writef("○%T", goTypeName(typ)) // cycle to typ
78                 return
79         }
80         w.seen[typ] = true
81         defer delete(w.seen, typ)
82
83         switch t := typ.(type) {
84         case nil:
85                 w.string("<nil>")
86
87         case *Basic:
88                 // exported basic types go into package unsafe
89                 // (currently this is just unsafe.Pointer)
90                 if isExported(t.name) {
91                         if obj, _ := Unsafe.scope.Lookup(t.name).(*TypeName); obj != nil {
92                                 w.typeName(obj)
93                                 break
94                         }
95                 }
96                 w.string(t.name)
97
98         case *Array:
99                 w.writef("[%d]", t.len)
100                 w.typ(t.elem)
101
102         case *Slice:
103                 w.string("[]")
104                 w.typ(t.elem)
105
106         case *Struct:
107                 w.string("struct{")
108                 for i, f := range t.fields {
109                         if i > 0 {
110                                 w.string("; ")
111                         }
112                         // This doesn't do the right thing for embedded type
113                         // aliases where we should print the alias name, not
114                         // the aliased type (see issue #44410).
115                         if !f.embedded {
116                                 w.string(f.name)
117                                 w.byte(' ')
118                         }
119                         w.typ(f.typ)
120                         if tag := t.Tag(i); tag != "" {
121                                 w.writef(" %q", tag)
122                         }
123                 }
124                 w.byte('}')
125
126         case *Pointer:
127                 w.byte('*')
128                 w.typ(t.base)
129
130         case *Tuple:
131                 w.tuple(t, false)
132
133         case *Signature:
134                 w.string("func")
135                 w.signature(t)
136
137         case *Union:
138                 // Unions only appear as (syntactic) embedded elements
139                 // in interfaces and syntactically cannot be empty.
140                 if t.Len() == 0 {
141                         panic("empty union")
142                 }
143                 for i, t := range t.terms {
144                         if i > 0 {
145                                 w.byte('|')
146                         }
147                         if t.tilde {
148                                 w.byte('~')
149                         }
150                         w.typ(t.typ)
151                 }
152
153         case *Interface:
154                 w.string("interface{")
155                 first := true
156                 for _, m := range t.methods {
157                         if !first {
158                                 w.string("; ")
159                         }
160                         first = false
161                         w.string(m.name)
162                         w.signature(m.typ.(*Signature))
163                 }
164                 for _, typ := range t.embeddeds {
165                         if !first {
166                                 w.string("; ")
167                         }
168                         first = false
169                         w.typ(typ)
170                 }
171                 w.byte('}')
172
173         case *Map:
174                 w.string("map[")
175                 w.typ(t.key)
176                 w.byte(']')
177                 w.typ(t.elem)
178
179         case *Chan:
180                 var s string
181                 var parens bool
182                 switch t.dir {
183                 case SendRecv:
184                         s = "chan "
185                         // chan (<-chan T) requires parentheses
186                         if c, _ := t.elem.(*Chan); c != nil && c.dir == RecvOnly {
187                                 parens = true
188                         }
189                 case SendOnly:
190                         s = "chan<- "
191                 case RecvOnly:
192                         s = "<-chan "
193                 default:
194                         unreachable()
195                 }
196                 w.string(s)
197                 if parens {
198                         w.byte('(')
199                 }
200                 w.typ(t.elem)
201                 if parens {
202                         w.byte(')')
203                 }
204
205         case *Named:
206                 if t.instPos != nil {
207                         w.byte(instanceMarker)
208                 }
209                 w.typeName(t.obj)
210                 if t.targs != nil {
211                         // instantiated type
212                         w.typeList(t.targs.list())
213                 } else if t.TParams().Len() != 0 {
214                         // parameterized type
215                         w.tParamList(t.TParams().list())
216                 }
217
218         case *TypeParam:
219                 s := "?"
220                 if t.obj != nil {
221                         // Optionally write out package for typeparams (like Named).
222                         // TODO(danscales): this is required for import/export, so
223                         // we maybe need a separate function that won't be changed
224                         // for debugging purposes.
225                         if t.obj.pkg != nil {
226                                 writePackage(w.buf, t.obj.pkg, w.qf)
227                         }
228                         s = t.obj.name
229                 }
230                 w.string(s + subscript(t.id))
231
232         case *top:
233                 w.string("⊤")
234
235         default:
236                 // For externally defined implementations of Type.
237                 // Note: In this case cycles won't be caught.
238                 w.string(t.String())
239         }
240 }
241
242 func (w *typeWriter) typeList(list []Type) {
243         w.byte('[')
244         for i, typ := range list {
245                 if i > 0 {
246                         w.string(", ")
247                 }
248                 w.typ(typ)
249         }
250         w.byte(']')
251 }
252
253 func (w *typeWriter) tParamList(list []*TypeParam) {
254         w.byte('[')
255         var prev Type
256         for i, tpar := range list {
257                 // Determine the type parameter and its constraint.
258                 // list is expected to hold type parameter names,
259                 // but don't crash if that's not the case.
260                 var bound Type
261                 if tpar != nil {
262                         bound = tpar.bound // should not be nil but we want to see it if it is
263                 }
264
265                 if i > 0 {
266                         if bound != prev {
267                                 // bound changed - write previous one before advancing
268                                 w.byte(' ')
269                                 w.typ(prev)
270                         }
271                         w.string(", ")
272                 }
273                 prev = bound
274
275                 if tpar != nil {
276                         w.typ(tpar)
277                 } else {
278                         w.string(tpar.obj.name)
279                 }
280         }
281         if prev != nil {
282                 w.byte(' ')
283                 w.typ(prev)
284         }
285         w.byte(']')
286 }
287
288 func (w *typeWriter) typeName(obj *TypeName) {
289         if obj == nil {
290                 assert(instanceHashing == 0) // we need an object for instance hashing
291                 w.string("<Named w/o object>")
292                 return
293         }
294         if obj.pkg != nil {
295                 writePackage(w.buf, obj.pkg, w.qf)
296         }
297         w.string(obj.name)
298
299         if instanceHashing != 0 {
300                 // For local defined types, use the (original!) TypeName's scope
301                 // numbers to disambiguate.
302                 typ := obj.typ.(*Named)
303                 // TODO(gri) Figure out why typ.orig != typ.orig.orig sometimes
304                 //           and whether the loop can iterate more than twice.
305                 //           (It seems somehow connected to instance types.)
306                 for typ.orig != typ {
307                         typ = typ.orig
308                 }
309                 w.writeScopeNumbers(typ.obj.parent)
310         }
311 }
312
313 // writeScopeNumbers writes the number sequence for this scope to buf
314 // in the form ".i.j.k" where i, j, k, etc. stand for scope numbers.
315 // If a scope is nil or has no parent (such as a package scope), nothing
316 // is written.
317 func (w *typeWriter) writeScopeNumbers(s *Scope) {
318         if s != nil && s.number > 0 {
319                 w.writeScopeNumbers(s.parent)
320                 w.writef(".%d", s.number)
321         }
322 }
323
324 func (w *typeWriter) tuple(tup *Tuple, variadic bool) {
325         w.byte('(')
326         if tup != nil {
327                 for i, v := range tup.vars {
328                         if i > 0 {
329                                 w.string(", ")
330                         }
331                         if v.name != "" {
332                                 w.string(v.name)
333                                 w.byte(' ')
334                         }
335                         typ := v.typ
336                         if variadic && i == len(tup.vars)-1 {
337                                 if s, ok := typ.(*Slice); ok {
338                                         w.string("...")
339                                         typ = s.elem
340                                 } else {
341                                         // special case:
342                                         // append(s, "foo"...) leads to signature func([]byte, string...)
343                                         if t := asBasic(typ); t == nil || t.kind != String {
344                                                 panic("expected string type")
345                                         }
346                                         w.typ(typ)
347                                         w.string("...")
348                                         continue
349                                 }
350                         }
351                         w.typ(typ)
352                 }
353         }
354         w.byte(')')
355 }
356
357 // WriteSignature writes the representation of the signature sig to buf,
358 // without a leading "func" keyword.
359 // The Qualifier controls the printing of
360 // package-level objects, and may be nil.
361 func WriteSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier) {
362         newTypeWriter(buf, qf).signature(sig)
363 }
364
365 func (w *typeWriter) signature(sig *Signature) {
366         if sig.TParams().Len() != 0 {
367                 w.tParamList(sig.TParams().list())
368         }
369
370         w.tuple(sig.params, sig.variadic)
371
372         n := sig.results.Len()
373         if n == 0 {
374                 // no result
375                 return
376         }
377
378         w.byte(' ')
379         if n == 1 && sig.results.vars[0].name == "" {
380                 // single unnamed result
381                 w.typ(sig.results.vars[0].typ)
382                 return
383         }
384
385         // multiple or named result(s)
386         w.tuple(sig.results, false)
387 }
388
389 // subscript returns the decimal (utf8) representation of x using subscript digits.
390 func subscript(x uint64) string {
391         const w = len("₀") // all digits 0...9 have the same utf8 width
392         var buf [32 * w]byte
393         i := len(buf)
394         for {
395                 i -= w
396                 utf8.EncodeRune(buf[i:], '₀'+rune(x%10)) // '₀' == U+2080
397                 x /= 10
398                 if x == 0 {
399                         break
400                 }
401         }
402         return string(buf[i:])
403 }