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