]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/types2/typestring.go
[dev.typeparams] cmd/compile/internal/types2: use converter functions rather than...
[gostls13.git] / src / cmd / compile / internal / types2 / typestring.go
1 // UNREVIEWED
2 // Copyright 2013 The Go Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style
4 // license that can be found in the LICENSE file.
5
6 // This file implements printing of types.
7
8 package types2
9
10 import (
11         "bytes"
12         "fmt"
13         "unicode/utf8"
14 )
15
16 // A Qualifier controls how named package-level objects are printed in
17 // calls to TypeString, ObjectString, and SelectionString.
18 //
19 // These three formatting routines call the Qualifier for each
20 // package-level object O, and if the Qualifier returns a non-empty
21 // string p, the object is printed in the form p.O.
22 // If it returns an empty string, only the object name O is printed.
23 //
24 // Using a nil Qualifier is equivalent to using (*Package).Path: the
25 // object is qualified by the import path, e.g., "encoding/json.Marshal".
26 //
27 type Qualifier func(*Package) string
28
29 // RelativeTo returns a Qualifier that fully qualifies members of
30 // all packages other than pkg.
31 func RelativeTo(pkg *Package) Qualifier {
32         if pkg == nil {
33                 return nil
34         }
35         return func(other *Package) string {
36                 if pkg == other {
37                         return "" // same package; unqualified
38                 }
39                 return other.Path()
40         }
41 }
42
43 // If gcCompatibilityMode is set, printing of types is modified
44 // to match the representation of some types in the gc compiler:
45 //
46 //      - byte and rune lose their alias name and simply stand for
47 //        uint8 and int32 respectively
48 //      - embedded interfaces get flattened (the embedding info is lost,
49 //        and certain recursive interface types cannot be printed anymore)
50 //
51 // This makes it easier to compare packages computed with the type-
52 // checker vs packages imported from gc export data.
53 //
54 // Caution: This flag affects all uses of WriteType, globally.
55 // It is only provided for testing in conjunction with
56 // gc-generated data.
57 //
58 // This flag is exported in the x/tools/go/types package. We don't
59 // need it at the moment in the std repo and so we don't export it
60 // anymore. We should eventually try to remove it altogether.
61 // TODO(gri) remove this
62 var gcCompatibilityMode bool
63
64 // TypeString returns the string representation of typ.
65 // The Qualifier controls the printing of
66 // package-level objects, and may be nil.
67 func TypeString(typ Type, qf Qualifier) string {
68         var buf bytes.Buffer
69         WriteType(&buf, typ, qf)
70         return buf.String()
71 }
72
73 // WriteType writes the string representation of typ to buf.
74 // The Qualifier controls the printing of
75 // package-level objects, and may be nil.
76 func WriteType(buf *bytes.Buffer, typ Type, qf Qualifier) {
77         writeType(buf, typ, qf, make([]Type, 0, 8))
78 }
79
80 // instanceMarker is the prefix for an instantiated type
81 // in "non-evaluated" instance form.
82 const instanceMarker = '#'
83
84 func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) {
85         // Theoretically, this is a quadratic lookup algorithm, but in
86         // practice deeply nested composite types with unnamed component
87         // types are uncommon. This code is likely more efficient than
88         // using a map.
89         for _, t := range visited {
90                 if t == typ {
91                         fmt.Fprintf(buf, "○%T", goTypeName(typ)) // cycle to typ
92                         return
93                 }
94         }
95         visited = append(visited, typ)
96
97         switch t := typ.(type) {
98         case nil:
99                 buf.WriteString("<nil>")
100
101         case *Basic:
102                 if t.kind == UnsafePointer {
103                         buf.WriteString("unsafe.")
104                 }
105                 if gcCompatibilityMode {
106                         // forget the alias names
107                         switch t.kind {
108                         case Byte:
109                                 t = Typ[Uint8]
110                         case Rune:
111                                 t = Typ[Int32]
112                         }
113                 }
114                 buf.WriteString(t.name)
115
116         case *Array:
117                 fmt.Fprintf(buf, "[%d]", t.len)
118                 writeType(buf, t.elem, qf, visited)
119
120         case *Slice:
121                 buf.WriteString("[]")
122                 writeType(buf, t.elem, qf, visited)
123
124         case *Struct:
125                 buf.WriteString("struct{")
126                 for i, f := range t.fields {
127                         if i > 0 {
128                                 buf.WriteString("; ")
129                         }
130                         buf.WriteString(f.name)
131                         if f.embedded {
132                                 // emphasize that the embedded field's name
133                                 // doesn't match the field's type name
134                                 if f.name != embeddedFieldName(f.typ) {
135                                         buf.WriteString(" /* = ")
136                                         writeType(buf, f.typ, qf, visited)
137                                         buf.WriteString(" */")
138                                 }
139                         } else {
140                                 buf.WriteByte(' ')
141                                 writeType(buf, f.typ, qf, visited)
142                         }
143                         if tag := t.Tag(i); tag != "" {
144                                 fmt.Fprintf(buf, " %q", tag)
145                         }
146                 }
147                 buf.WriteByte('}')
148
149         case *Pointer:
150                 buf.WriteByte('*')
151                 writeType(buf, t.base, qf, visited)
152
153         case *Tuple:
154                 writeTuple(buf, t, false, qf, visited)
155
156         case *Signature:
157                 buf.WriteString("func")
158                 writeSignature(buf, t, qf, visited)
159
160         case *Sum:
161                 for i, t := range t.types {
162                         if i > 0 {
163                                 buf.WriteString(", ")
164                         }
165                         writeType(buf, t, qf, visited)
166                 }
167
168         case *Interface:
169                 // We write the source-level methods and embedded types rather
170                 // than the actual method set since resolved method signatures
171                 // may have non-printable cycles if parameters have embedded
172                 // interface types that (directly or indirectly) embed the
173                 // current interface. For instance, consider the result type
174                 // of m:
175                 //
176                 //     type T interface{
177                 //         m() interface{ T }
178                 //     }
179                 //
180                 buf.WriteString("interface{")
181                 empty := true
182                 if gcCompatibilityMode {
183                         // print flattened interface
184                         // (useful to compare against gc-generated interfaces)
185                         for i, m := range t.allMethods {
186                                 if i > 0 {
187                                         buf.WriteString("; ")
188                                 }
189                                 buf.WriteString(m.name)
190                                 writeSignature(buf, m.typ.(*Signature), qf, visited)
191                                 empty = false
192                         }
193                         if !empty && t.allTypes != nil {
194                                 buf.WriteString("; ")
195                         }
196                         if t.allTypes != nil {
197                                 buf.WriteString("type ")
198                                 writeType(buf, t.allTypes, qf, visited)
199                         }
200                 } else {
201                         // print explicit interface methods and embedded types
202                         for i, m := range t.methods {
203                                 if i > 0 {
204                                         buf.WriteString("; ")
205                                 }
206                                 buf.WriteString(m.name)
207                                 writeSignature(buf, m.typ.(*Signature), qf, visited)
208                                 empty = false
209                         }
210                         if !empty && t.types != nil {
211                                 buf.WriteString("; ")
212                         }
213                         if t.types != nil {
214                                 buf.WriteString("type ")
215                                 writeType(buf, t.types, qf, visited)
216                                 empty = false
217                         }
218                         if !empty && len(t.embeddeds) > 0 {
219                                 buf.WriteString("; ")
220                         }
221                         for i, typ := range t.embeddeds {
222                                 if i > 0 {
223                                         buf.WriteString("; ")
224                                 }
225                                 writeType(buf, typ, qf, visited)
226                                 empty = false
227                         }
228                 }
229                 if t.allMethods == nil || len(t.methods) > len(t.allMethods) {
230                         if !empty {
231                                 buf.WriteByte(' ')
232                         }
233                         buf.WriteString("/* incomplete */")
234                 }
235                 buf.WriteByte('}')
236
237         case *Map:
238                 buf.WriteString("map[")
239                 writeType(buf, t.key, qf, visited)
240                 buf.WriteByte(']')
241                 writeType(buf, t.elem, qf, visited)
242
243         case *Chan:
244                 var s string
245                 var parens bool
246                 switch t.dir {
247                 case SendRecv:
248                         s = "chan "
249                         // chan (<-chan T) requires parentheses
250                         if c, _ := t.elem.(*Chan); c != nil && c.dir == RecvOnly {
251                                 parens = true
252                         }
253                 case SendOnly:
254                         s = "chan<- "
255                 case RecvOnly:
256                         s = "<-chan "
257                 default:
258                         panic("unreachable")
259                 }
260                 buf.WriteString(s)
261                 if parens {
262                         buf.WriteByte('(')
263                 }
264                 writeType(buf, t.elem, qf, visited)
265                 if parens {
266                         buf.WriteByte(')')
267                 }
268
269         case *Named:
270                 writeTypeName(buf, t.obj, qf)
271                 if t.targs != nil {
272                         // instantiated type
273                         buf.WriteByte('[')
274                         writeTypeList(buf, t.targs, qf, visited)
275                         buf.WriteByte(']')
276                 } else if t.tparams != nil {
277                         // parameterized type
278                         writeTParamList(buf, t.tparams, qf, visited)
279                 }
280
281         case *TypeParam:
282                 s := "?"
283                 if t.obj != nil {
284                         s = t.obj.name
285                 }
286                 buf.WriteString(s + subscript(t.id))
287
288         case *instance:
289                 buf.WriteByte(instanceMarker) // indicate "non-evaluated" syntactic instance
290                 writeTypeName(buf, t.base.obj, qf)
291                 buf.WriteByte('[')
292                 writeTypeList(buf, t.targs, qf, visited)
293                 buf.WriteByte(']')
294
295         case *bottom:
296                 buf.WriteString("⊥")
297
298         case *top:
299                 buf.WriteString("⊤")
300
301         default:
302                 // For externally defined implementations of Type.
303                 buf.WriteString(t.String())
304         }
305 }
306
307 func writeTypeList(buf *bytes.Buffer, list []Type, qf Qualifier, visited []Type) {
308         for i, typ := range list {
309                 if i > 0 {
310                         buf.WriteString(", ")
311                 }
312                 writeType(buf, typ, qf, visited)
313         }
314 }
315
316 func writeTParamList(buf *bytes.Buffer, list []*TypeName, qf Qualifier, visited []Type) {
317         // bound returns the type bound for tname. The result is never nil.
318         bound := func(tname *TypeName) Type {
319                 // be careful to avoid crashes in case of inconsistencies
320                 if t, _ := tname.typ.(*TypeParam); t != nil && t.bound != nil {
321                         return t.bound
322                 }
323                 return &emptyInterface
324         }
325
326         // If a single type bound is not the empty interface, we have to write them all.
327         var writeBounds bool
328         for _, p := range list {
329                 // bound(p) should be an interface but be careful (it may be invalid)
330                 b := asInterface(bound(p))
331                 if b != nil && !b.Empty() {
332                         writeBounds = true
333                         break
334                 }
335         }
336         writeBounds = true // always write the bounds for new type parameter list syntax
337
338         buf.WriteString("[")
339         var prev Type
340         for i, p := range list {
341                 b := bound(p)
342                 if i > 0 {
343                         if writeBounds && b != prev {
344                                 // type bound changed - write previous one before advancing
345                                 buf.WriteByte(' ')
346                                 writeType(buf, prev, qf, visited)
347                         }
348                         buf.WriteString(", ")
349                 }
350                 prev = b
351
352                 if t, _ := p.typ.(*TypeParam); t != nil {
353                         writeType(buf, t, qf, visited)
354                 } else {
355                         buf.WriteString(p.name)
356                 }
357         }
358         if writeBounds && prev != nil {
359                 buf.WriteByte(' ')
360                 writeType(buf, prev, qf, visited)
361         }
362         buf.WriteByte(']')
363 }
364
365 func writeTypeName(buf *bytes.Buffer, obj *TypeName, qf Qualifier) {
366         s := "<Named w/o object>"
367         if obj != nil {
368                 if obj.pkg != nil {
369                         writePackage(buf, obj.pkg, qf)
370                 }
371                 // TODO(gri): function-local named types should be displayed
372                 // differently from named types at package level to avoid
373                 // ambiguity.
374                 s = obj.name
375         }
376         buf.WriteString(s)
377 }
378
379 func writeTuple(buf *bytes.Buffer, tup *Tuple, variadic bool, qf Qualifier, visited []Type) {
380         buf.WriteByte('(')
381         if tup != nil {
382                 for i, v := range tup.vars {
383                         if i > 0 {
384                                 buf.WriteString(", ")
385                         }
386                         if v.name != "" {
387                                 buf.WriteString(v.name)
388                                 buf.WriteByte(' ')
389                         }
390                         typ := v.typ
391                         if variadic && i == len(tup.vars)-1 {
392                                 if s, ok := typ.(*Slice); ok {
393                                         buf.WriteString("...")
394                                         typ = s.elem
395                                 } else {
396                                         // special case:
397                                         // append(s, "foo"...) leads to signature func([]byte, string...)
398                                         if t := asBasic(typ); t == nil || t.kind != String {
399                                                 panic("internal error: string type expected")
400                                         }
401                                         writeType(buf, typ, qf, visited)
402                                         buf.WriteString("...")
403                                         continue
404                                 }
405                         }
406                         writeType(buf, typ, qf, visited)
407                 }
408         }
409         buf.WriteByte(')')
410 }
411
412 // WriteSignature writes the representation of the signature sig to buf,
413 // without a leading "func" keyword.
414 // The Qualifier controls the printing of
415 // package-level objects, and may be nil.
416 func WriteSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier) {
417         writeSignature(buf, sig, qf, make([]Type, 0, 8))
418 }
419
420 func writeSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier, visited []Type) {
421         if sig.tparams != nil {
422                 writeTParamList(buf, sig.tparams, qf, visited)
423         }
424
425         writeTuple(buf, sig.params, sig.variadic, qf, visited)
426
427         n := sig.results.Len()
428         if n == 0 {
429                 // no result
430                 return
431         }
432
433         buf.WriteByte(' ')
434         if n == 1 && sig.results.vars[0].name == "" {
435                 // single unnamed result
436                 writeType(buf, sig.results.vars[0].typ, qf, visited)
437                 return
438         }
439
440         // multiple or named result(s)
441         writeTuple(buf, sig.results, false, qf, visited)
442 }
443
444 // embeddedFieldName returns an embedded field's name given its type.
445 // The result is "" if the type doesn't have an embedded field name.
446 func embeddedFieldName(typ Type) string {
447         switch t := typ.(type) {
448         case *Basic:
449                 return t.name
450         case *Named:
451                 return t.obj.name
452         case *Pointer:
453                 // *T is ok, but **T is not
454                 if _, ok := t.base.(*Pointer); !ok {
455                         return embeddedFieldName(t.base)
456                 }
457         case *instance:
458                 return t.base.obj.name
459         }
460         return "" // not a (pointer to) a defined type
461 }
462
463 // subscript returns the decimal (utf8) representation of x using subscript digits.
464 func subscript(x uint64) string {
465         const w = len("₀") // all digits 0...9 have the same utf8 width
466         var buf [32 * w]byte
467         i := len(buf)
468         for {
469                 i -= w
470                 utf8.EncodeRune(buf[i:], '₀'+rune(x%10)) // '₀' == U+2080
471                 x /= 10
472                 if x == 0 {
473                         break
474                 }
475         }
476         return string(buf[i:])
477 }