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