]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/types2/typestring.go
cmd/compile/internal/types2: eliminate Named.instPos
[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         env  *Environment // 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, env *Environment) *typeWriter {
78         assert(env != nil)
79         return &typeWriter{buf, make(map[Type]bool), nil, env}
80 }
81
82 func (w *typeWriter) byte(b byte) {
83         if w.env != 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.env != 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 Environment.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                 w.string("interface{")
194                 first := true
195                 for _, m := range t.methods {
196                         if !first {
197                                 w.byte(';')
198                         }
199                         first = false
200                         w.string(m.name)
201                         w.signature(m.typ.(*Signature))
202                 }
203                 for _, typ := range t.embeddeds {
204                         if !first {
205                                 w.byte(';')
206                         }
207                         first = false
208                         w.typ(typ)
209                 }
210                 w.byte('}')
211
212         case *Map:
213                 w.string("map[")
214                 w.typ(t.key)
215                 w.byte(']')
216                 w.typ(t.elem)
217
218         case *Chan:
219                 var s string
220                 var parens bool
221                 switch t.dir {
222                 case SendRecv:
223                         s = "chan "
224                         // chan (<-chan T) requires parentheses
225                         if c, _ := t.elem.(*Chan); c != nil && c.dir == RecvOnly {
226                                 parens = true
227                         }
228                 case SendOnly:
229                         s = "chan<- "
230                 case RecvOnly:
231                         s = "<-chan "
232                 default:
233                         w.error("unknown channel direction")
234                 }
235                 w.string(s)
236                 if parens {
237                         w.byte('(')
238                 }
239                 w.typ(t.elem)
240                 if parens {
241                         w.byte(')')
242                 }
243
244         case *Named:
245                 w.typePrefix(t)
246                 w.typeName(t.obj)
247                 if t.targs != nil {
248                         // instantiated type
249                         w.typeList(t.targs.list())
250                 } else if w.env == nil && t.TypeParams().Len() != 0 { // For type hashing, don't need to format the TParams
251                         // parameterized type
252                         w.tParamList(t.TypeParams().list())
253                 }
254
255         case *TypeParam:
256                 if t.obj == nil {
257                         w.error("unnamed type parameter")
258                         break
259                 }
260                 // Optionally write out package for typeparams (like Named).
261                 // TODO(danscales): this is required for import/export, so
262                 // we maybe need a separate function that won't be changed
263                 // for debugging purposes.
264                 if t.obj.pkg != nil {
265                         writePackage(w.buf, t.obj.pkg, w.qf)
266                 }
267                 w.string(t.obj.name + subscript(t.id))
268
269         case *top:
270                 w.error("⊤")
271
272         default:
273                 // For externally defined implementations of Type.
274                 // Note: In this case cycles won't be caught.
275                 w.string(t.String())
276         }
277 }
278
279 // If w.env is non-nil, typePrefix writes a unique prefix for the named type t
280 // based on the types already observed by w.env. If w.env is nil, it does
281 // nothing.
282 func (w *typeWriter) typePrefix(t *Named) {
283         if w.env != nil {
284                 w.string(strconv.Itoa(w.env.idForType(t)))
285         }
286 }
287
288 func (w *typeWriter) typeList(list []Type) {
289         w.byte('[')
290         for i, typ := range list {
291                 if i > 0 {
292                         w.byte(',')
293                 }
294                 w.typ(typ)
295         }
296         w.byte(']')
297 }
298
299 func (w *typeWriter) tParamList(list []*TypeParam) {
300         w.byte('[')
301         var prev Type
302         for i, tpar := range list {
303                 // Determine the type parameter and its constraint.
304                 // list is expected to hold type parameter names,
305                 // but don't crash if that's not the case.
306                 if tpar == nil {
307                         w.error("nil type parameter")
308                         continue
309                 }
310                 if i > 0 {
311                         if tpar.bound != prev {
312                                 // bound changed - write previous one before advancing
313                                 w.byte(' ')
314                                 w.typ(prev)
315                         }
316                         w.byte(',')
317                 }
318                 prev = tpar.bound
319                 w.typ(tpar)
320         }
321         if prev != nil {
322                 w.byte(' ')
323                 w.typ(prev)
324         }
325         w.byte(']')
326 }
327
328 func (w *typeWriter) typeName(obj *TypeName) {
329         if obj.pkg != nil {
330                 writePackage(w.buf, obj.pkg, w.qf)
331         }
332         w.string(obj.name)
333 }
334
335 func (w *typeWriter) tuple(tup *Tuple, variadic bool) {
336         w.byte('(')
337         if tup != nil {
338                 for i, v := range tup.vars {
339                         if i > 0 {
340                                 w.byte(',')
341                         }
342                         // parameter names are ignored for type identity and thus type hashes
343                         if w.env == nil && v.name != "" {
344                                 w.string(v.name)
345                                 w.byte(' ')
346                         }
347                         typ := v.typ
348                         if variadic && i == len(tup.vars)-1 {
349                                 if s, ok := typ.(*Slice); ok {
350                                         w.string("...")
351                                         typ = s.elem
352                                 } else {
353                                         // special case:
354                                         // append(s, "foo"...) leads to signature func([]byte, string...)
355                                         if t := asBasic(typ); t == nil || t.kind != String {
356                                                 w.error("expected string type")
357                                                 continue
358                                         }
359                                         w.typ(typ)
360                                         w.string("...")
361                                         continue
362                                 }
363                         }
364                         w.typ(typ)
365                 }
366         }
367         w.byte(')')
368 }
369
370 func (w *typeWriter) signature(sig *Signature) {
371         if sig.TypeParams().Len() != 0 {
372                 w.tParamList(sig.TypeParams().list())
373         }
374
375         w.tuple(sig.params, sig.variadic)
376
377         n := sig.results.Len()
378         if n == 0 {
379                 // no result
380                 return
381         }
382
383         w.byte(' ')
384         if n == 1 && (w.env != nil || sig.results.vars[0].name == "") {
385                 // single unnamed result (if type hashing, name must be ignored)
386                 w.typ(sig.results.vars[0].typ)
387                 return
388         }
389
390         // multiple or named result(s)
391         w.tuple(sig.results, false)
392 }
393
394 // subscript returns the decimal (utf8) representation of x using subscript digits.
395 func subscript(x uint64) string {
396         const w = len("₀") // all digits 0...9 have the same utf8 width
397         var buf [32 * w]byte
398         i := len(buf)
399         for {
400                 i -= w
401                 utf8.EncodeRune(buf[i:], '₀'+rune(x%10)) // '₀' == U+2080
402                 x /= 10
403                 if x == 0 {
404                         break
405                 }
406         }
407         return string(buf[i:])
408 }