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