]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/types2/typestring.go
all: REVERSE MERGE dev.typeparams (7cdfa49) into master
[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                         // This doesn't do the right thing for embedded type
130                         // aliases where we should print the alias name, not
131                         // the aliased type (see issue #44410).
132                         if !f.embedded {
133                                 buf.WriteString(f.name)
134                                 buf.WriteByte(' ')
135                         }
136                         writeType(buf, f.typ, qf, visited)
137                         if tag := t.Tag(i); tag != "" {
138                                 fmt.Fprintf(buf, " %q", tag)
139                         }
140                 }
141                 buf.WriteByte('}')
142
143         case *Pointer:
144                 buf.WriteByte('*')
145                 writeType(buf, t.base, qf, visited)
146
147         case *Tuple:
148                 writeTuple(buf, t, false, qf, visited)
149
150         case *Signature:
151                 buf.WriteString("func")
152                 writeSignature(buf, t, qf, visited)
153
154         case *Sum:
155                 for i, t := range t.types {
156                         if i > 0 {
157                                 buf.WriteString(", ")
158                         }
159                         writeType(buf, t, qf, visited)
160                 }
161
162         case *Interface:
163                 // We write the source-level methods and embedded types rather
164                 // than the actual method set since resolved method signatures
165                 // may have non-printable cycles if parameters have embedded
166                 // interface types that (directly or indirectly) embed the
167                 // current interface. For instance, consider the result type
168                 // of m:
169                 //
170                 //     type T interface{
171                 //         m() interface{ T }
172                 //     }
173                 //
174                 buf.WriteString("interface{")
175                 empty := true
176                 if gcCompatibilityMode {
177                         // print flattened interface
178                         // (useful to compare against gc-generated interfaces)
179                         for i, m := range t.allMethods {
180                                 if i > 0 {
181                                         buf.WriteString("; ")
182                                 }
183                                 buf.WriteString(m.name)
184                                 writeSignature(buf, m.typ.(*Signature), qf, visited)
185                                 empty = false
186                         }
187                         if !empty && t.allTypes != nil {
188                                 buf.WriteString("; ")
189                         }
190                         if t.allTypes != nil {
191                                 buf.WriteString("type ")
192                                 writeType(buf, t.allTypes, qf, visited)
193                         }
194                 } else {
195                         // print explicit interface methods and embedded types
196                         for i, m := range t.methods {
197                                 if i > 0 {
198                                         buf.WriteString("; ")
199                                 }
200                                 buf.WriteString(m.name)
201                                 writeSignature(buf, m.typ.(*Signature), qf, visited)
202                                 empty = false
203                         }
204                         if !empty && t.types != nil {
205                                 buf.WriteString("; ")
206                         }
207                         if t.types != nil {
208                                 buf.WriteString("type ")
209                                 writeType(buf, t.types, qf, visited)
210                                 empty = false
211                         }
212                         if !empty && len(t.embeddeds) > 0 {
213                                 buf.WriteString("; ")
214                         }
215                         for i, typ := range t.embeddeds {
216                                 if i > 0 {
217                                         buf.WriteString("; ")
218                                 }
219                                 writeType(buf, typ, qf, visited)
220                                 empty = false
221                         }
222                 }
223                 if t.allMethods == nil || len(t.methods) > len(t.allMethods) {
224                         if !empty {
225                                 buf.WriteByte(' ')
226                         }
227                         buf.WriteString("/* incomplete */")
228                 }
229                 buf.WriteByte('}')
230
231         case *Map:
232                 buf.WriteString("map[")
233                 writeType(buf, t.key, qf, visited)
234                 buf.WriteByte(']')
235                 writeType(buf, t.elem, qf, visited)
236
237         case *Chan:
238                 var s string
239                 var parens bool
240                 switch t.dir {
241                 case SendRecv:
242                         s = "chan "
243                         // chan (<-chan T) requires parentheses
244                         if c, _ := t.elem.(*Chan); c != nil && c.dir == RecvOnly {
245                                 parens = true
246                         }
247                 case SendOnly:
248                         s = "chan<- "
249                 case RecvOnly:
250                         s = "<-chan "
251                 default:
252                         panic("unreachable")
253                 }
254                 buf.WriteString(s)
255                 if parens {
256                         buf.WriteByte('(')
257                 }
258                 writeType(buf, t.elem, qf, visited)
259                 if parens {
260                         buf.WriteByte(')')
261                 }
262
263         case *Named:
264                 writeTypeName(buf, t.obj, qf)
265                 if t.targs != nil {
266                         // instantiated type
267                         buf.WriteByte('[')
268                         writeTypeList(buf, t.targs, qf, visited)
269                         buf.WriteByte(']')
270                 } else if t.tparams != nil {
271                         // parameterized type
272                         writeTParamList(buf, t.tparams, qf, visited)
273                 }
274
275         case *TypeParam:
276                 s := "?"
277                 if t.obj != nil {
278                         s = t.obj.name
279                 }
280                 buf.WriteString(s + subscript(t.id))
281
282         case *instance:
283                 buf.WriteByte(instanceMarker) // indicate "non-evaluated" syntactic instance
284                 writeTypeName(buf, t.base.obj, qf)
285                 buf.WriteByte('[')
286                 writeTypeList(buf, t.targs, qf, visited)
287                 buf.WriteByte(']')
288
289         case *bottom:
290                 buf.WriteString("⊥")
291
292         case *top:
293                 buf.WriteString("⊤")
294
295         default:
296                 // For externally defined implementations of Type.
297                 buf.WriteString(t.String())
298         }
299 }
300
301 func writeTypeList(buf *bytes.Buffer, list []Type, qf Qualifier, visited []Type) {
302         for i, typ := range list {
303                 if i > 0 {
304                         buf.WriteString(", ")
305                 }
306                 writeType(buf, typ, qf, visited)
307         }
308 }
309
310 func writeTParamList(buf *bytes.Buffer, list []*TypeName, qf Qualifier, visited []Type) {
311         buf.WriteString("[")
312         var prev Type
313         for i, p := range list {
314                 // TODO(gri) support 'any' sugar here.
315                 var b Type = &emptyInterface
316                 if t, _ := p.typ.(*TypeParam); t != nil && t.bound != nil {
317                         b = t.bound
318                 }
319                 if i > 0 {
320                         if b != prev {
321                                 // type bound changed - write previous one before advancing
322                                 buf.WriteByte(' ')
323                                 writeType(buf, prev, qf, visited)
324                         }
325                         buf.WriteString(", ")
326                 }
327                 prev = b
328
329                 if t, _ := p.typ.(*TypeParam); t != nil {
330                         writeType(buf, t, qf, visited)
331                 } else {
332                         buf.WriteString(p.name)
333                 }
334         }
335         if prev != nil {
336                 buf.WriteByte(' ')
337                 writeType(buf, prev, qf, visited)
338         }
339         buf.WriteByte(']')
340 }
341
342 func writeTypeName(buf *bytes.Buffer, obj *TypeName, qf Qualifier) {
343         s := "<Named w/o object>"
344         if obj != nil {
345                 if obj.pkg != nil {
346                         writePackage(buf, obj.pkg, qf)
347                 }
348                 // TODO(gri): function-local named types should be displayed
349                 // differently from named types at package level to avoid
350                 // ambiguity.
351                 s = obj.name
352         }
353         buf.WriteString(s)
354 }
355
356 func writeTuple(buf *bytes.Buffer, tup *Tuple, variadic bool, qf Qualifier, visited []Type) {
357         buf.WriteByte('(')
358         if tup != nil {
359                 for i, v := range tup.vars {
360                         if i > 0 {
361                                 buf.WriteString(", ")
362                         }
363                         if v.name != "" {
364                                 buf.WriteString(v.name)
365                                 buf.WriteByte(' ')
366                         }
367                         typ := v.typ
368                         if variadic && i == len(tup.vars)-1 {
369                                 if s, ok := typ.(*Slice); ok {
370                                         buf.WriteString("...")
371                                         typ = s.elem
372                                 } else {
373                                         // special case:
374                                         // append(s, "foo"...) leads to signature func([]byte, string...)
375                                         if t := asBasic(typ); t == nil || t.kind != String {
376                                                 panic("internal error: string type expected")
377                                         }
378                                         writeType(buf, typ, qf, visited)
379                                         buf.WriteString("...")
380                                         continue
381                                 }
382                         }
383                         writeType(buf, typ, qf, visited)
384                 }
385         }
386         buf.WriteByte(')')
387 }
388
389 // WriteSignature writes the representation of the signature sig to buf,
390 // without a leading "func" keyword.
391 // The Qualifier controls the printing of
392 // package-level objects, and may be nil.
393 func WriteSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier) {
394         writeSignature(buf, sig, qf, make([]Type, 0, 8))
395 }
396
397 func writeSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier, visited []Type) {
398         if sig.tparams != nil {
399                 writeTParamList(buf, sig.tparams, qf, visited)
400         }
401
402         writeTuple(buf, sig.params, sig.variadic, qf, visited)
403
404         n := sig.results.Len()
405         if n == 0 {
406                 // no result
407                 return
408         }
409
410         buf.WriteByte(' ')
411         if n == 1 && sig.results.vars[0].name == "" {
412                 // single unnamed result
413                 writeType(buf, sig.results.vars[0].typ, qf, visited)
414                 return
415         }
416
417         // multiple or named result(s)
418         writeTuple(buf, sig.results, false, qf, visited)
419 }
420
421 // subscript returns the decimal (utf8) representation of x using subscript digits.
422 func subscript(x uint64) string {
423         const w = len("₀") // all digits 0...9 have the same utf8 width
424         var buf [32 * w]byte
425         i := len(buf)
426         for {
427                 i -= w
428                 utf8.EncodeRune(buf[i:], '₀'+rune(x%10)) // '₀' == U+2080
429                 x /= 10
430                 if x == 0 {
431                         break
432                 }
433         }
434         return string(buf[i:])
435 }