]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/types2/typestring.go
cmd/compile/internal/types2: spell out 'Type' in type parameter APIs
[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         "strconv"
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 // TypeString returns the string representation of typ.
44 // The Qualifier controls the printing of
45 // package-level objects, and may be nil.
46 func TypeString(typ Type, qf Qualifier) string {
47         var buf bytes.Buffer
48         WriteType(&buf, typ, qf)
49         return buf.String()
50 }
51
52 // WriteType writes the string representation of typ to buf.
53 // The Qualifier controls the printing of
54 // package-level objects, and may be nil.
55 func WriteType(buf *bytes.Buffer, typ Type, qf Qualifier) {
56         newTypeWriter(buf, qf).typ(typ)
57 }
58
59 // WriteSignature writes the representation of the signature sig to buf,
60 // without a leading "func" keyword.
61 // The Qualifier controls the printing of
62 // package-level objects, and may be nil.
63 func WriteSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier) {
64         newTypeWriter(buf, qf).signature(sig)
65 }
66
67 // instanceMarker is the prefix for an instantiated type in unexpanded form.
68 const instanceMarker = '#'
69
70 type typeWriter struct {
71         buf  *bytes.Buffer
72         seen map[Type]bool
73         qf   Qualifier
74         env  *Environment // if non-nil, we are type hashing
75 }
76
77 func newTypeWriter(buf *bytes.Buffer, qf Qualifier) *typeWriter {
78         return &typeWriter{buf, make(map[Type]bool), qf, nil}
79 }
80
81 func newTypeHasher(buf *bytes.Buffer, env *Environment) *typeWriter {
82         assert(env != nil)
83         return &typeWriter{buf, make(map[Type]bool), nil, env}
84 }
85
86 func (w *typeWriter) byte(b byte)                               { w.buf.WriteByte(b) }
87 func (w *typeWriter) string(s string)                           { w.buf.WriteString(s) }
88 func (w *typeWriter) writef(format string, args ...interface{}) { fmt.Fprintf(w.buf, format, args...) }
89 func (w *typeWriter) error(msg string) {
90         if w.env != nil {
91                 panic(msg)
92         }
93         w.string("<" + msg + ">")
94 }
95
96 func (w *typeWriter) typ(typ Type) {
97         if w.seen[typ] {
98                 w.error("cycle to " + goTypeName(typ))
99                 return
100         }
101         w.seen[typ] = true
102         defer delete(w.seen, typ)
103
104         switch t := typ.(type) {
105         case nil:
106                 w.error("nil")
107
108         case *Basic:
109                 // exported basic types go into package unsafe
110                 // (currently this is just unsafe.Pointer)
111                 if isExported(t.name) {
112                         if obj, _ := Unsafe.scope.Lookup(t.name).(*TypeName); obj != nil {
113                                 w.typeName(obj)
114                                 break
115                         }
116                 }
117                 w.string(t.name)
118
119         case *Array:
120                 w.writef("[%d]", t.len)
121                 w.typ(t.elem)
122
123         case *Slice:
124                 w.string("[]")
125                 w.typ(t.elem)
126
127         case *Struct:
128                 w.string("struct{")
129                 for i, f := range t.fields {
130                         if i > 0 {
131                                 w.string("; ")
132                         }
133                         // This doesn't do the right thing for embedded type
134                         // aliases where we should print the alias name, not
135                         // the aliased type (see issue #44410).
136                         if !f.embedded {
137                                 w.string(f.name)
138                                 w.byte(' ')
139                         }
140                         w.typ(f.typ)
141                         if tag := t.Tag(i); tag != "" {
142                                 w.writef(" %q", tag)
143                         }
144                 }
145                 w.byte('}')
146
147         case *Pointer:
148                 w.byte('*')
149                 w.typ(t.base)
150
151         case *Tuple:
152                 w.tuple(t, false)
153
154         case *Signature:
155                 w.string("func")
156                 w.signature(t)
157
158         case *Union:
159                 // Unions only appear as (syntactic) embedded elements
160                 // in interfaces and syntactically cannot be empty.
161                 if t.Len() == 0 {
162                         w.error("empty union")
163                         break
164                 }
165                 for i, t := range t.terms {
166                         if i > 0 {
167                                 w.byte('|')
168                         }
169                         if t.tilde {
170                                 w.byte('~')
171                         }
172                         w.typ(t.typ)
173                 }
174
175         case *Interface:
176                 w.string("interface{")
177                 first := true
178                 for _, m := range t.methods {
179                         if !first {
180                                 w.string("; ")
181                         }
182                         first = false
183                         w.string(m.name)
184                         w.signature(m.typ.(*Signature))
185                 }
186                 for _, typ := range t.embeddeds {
187                         if !first {
188                                 w.string("; ")
189                         }
190                         first = false
191                         w.typ(typ)
192                 }
193                 w.byte('}')
194
195         case *Map:
196                 w.string("map[")
197                 w.typ(t.key)
198                 w.byte(']')
199                 w.typ(t.elem)
200
201         case *Chan:
202                 var s string
203                 var parens bool
204                 switch t.dir {
205                 case SendRecv:
206                         s = "chan "
207                         // chan (<-chan T) requires parentheses
208                         if c, _ := t.elem.(*Chan); c != nil && c.dir == RecvOnly {
209                                 parens = true
210                         }
211                 case SendOnly:
212                         s = "chan<- "
213                 case RecvOnly:
214                         s = "<-chan "
215                 default:
216                         w.error("unknown channel direction")
217                 }
218                 w.string(s)
219                 if parens {
220                         w.byte('(')
221                 }
222                 w.typ(t.elem)
223                 if parens {
224                         w.byte(')')
225                 }
226
227         case *Named:
228                 // Instance markers indicate unexpanded instantiated
229                 // types. Write them to aid debugging, but don't write
230                 // them when we need an instance hash: whether a type
231                 // is fully expanded or not doesn't matter for identity.
232                 if w.env == nil && t.instPos != nil {
233                         w.byte(instanceMarker)
234                 }
235                 w.typePrefix(t)
236                 w.typeName(t.obj)
237                 if t.targs != nil {
238                         // instantiated type
239                         w.typeList(t.targs.list())
240                 } else if w.env == nil && t.TypeParams().Len() != 0 { // For type hashing, don't need to format the TParams
241                         // parameterized type
242                         w.tParamList(t.TypeParams().list())
243                 }
244
245         case *TypeParam:
246                 if t.obj == nil {
247                         w.error("unnamed type parameter")
248                         break
249                 }
250                 // Optionally write out package for typeparams (like Named).
251                 // TODO(danscales): this is required for import/export, so
252                 // we maybe need a separate function that won't be changed
253                 // for debugging purposes.
254                 if t.obj.pkg != nil {
255                         writePackage(w.buf, t.obj.pkg, w.qf)
256                 }
257                 w.string(t.obj.name + subscript(t.id))
258
259         case *top:
260                 w.error("⊤")
261
262         default:
263                 // For externally defined implementations of Type.
264                 // Note: In this case cycles won't be caught.
265                 w.string(t.String())
266         }
267 }
268
269 // If w.env is non-nil, typePrefix writes a unique prefix for the named type t
270 // based on the types already observed by w.env. If w.env is nil, it does
271 // nothing.
272 func (w *typeWriter) typePrefix(t *Named) {
273         if w.env != nil {
274                 w.string(strconv.Itoa(w.env.idForType(t)))
275         }
276 }
277
278 func (w *typeWriter) typeList(list []Type) {
279         w.byte('[')
280         for i, typ := range list {
281                 if i > 0 {
282                         w.string(", ")
283                 }
284                 w.typ(typ)
285         }
286         w.byte(']')
287 }
288
289 func (w *typeWriter) tParamList(list []*TypeParam) {
290         w.byte('[')
291         var prev Type
292         for i, tpar := range list {
293                 // Determine the type parameter and its constraint.
294                 // list is expected to hold type parameter names,
295                 // but don't crash if that's not the case.
296                 if tpar == nil {
297                         w.error("nil type parameter")
298                         continue
299                 }
300                 if i > 0 {
301                         if tpar.bound != prev {
302                                 // bound changed - write previous one before advancing
303                                 w.byte(' ')
304                                 w.typ(prev)
305                         }
306                         w.string(", ")
307                 }
308                 prev = tpar.bound
309                 w.typ(tpar)
310         }
311         if prev != nil {
312                 w.byte(' ')
313                 w.typ(prev)
314         }
315         w.byte(']')
316 }
317
318 func (w *typeWriter) typeName(obj *TypeName) {
319         if obj.pkg != nil {
320                 writePackage(w.buf, obj.pkg, w.qf)
321         }
322         w.string(obj.name)
323 }
324
325 func (w *typeWriter) tuple(tup *Tuple, variadic bool) {
326         w.byte('(')
327         if tup != nil {
328                 for i, v := range tup.vars {
329                         if i > 0 {
330                                 w.string(", ")
331                         }
332                         // parameter names are ignored for type identity and thus type hashes
333                         if w.env == nil && v.name != "" {
334                                 w.string(v.name)
335                                 w.byte(' ')
336                         }
337                         typ := v.typ
338                         if variadic && i == len(tup.vars)-1 {
339                                 if s, ok := typ.(*Slice); ok {
340                                         w.string("...")
341                                         typ = s.elem
342                                 } else {
343                                         // special case:
344                                         // append(s, "foo"...) leads to signature func([]byte, string...)
345                                         if t := asBasic(typ); t == nil || t.kind != String {
346                                                 w.error("expected string type")
347                                                 continue
348                                         }
349                                         w.typ(typ)
350                                         w.string("...")
351                                         continue
352                                 }
353                         }
354                         w.typ(typ)
355                 }
356         }
357         w.byte(')')
358 }
359
360 func (w *typeWriter) signature(sig *Signature) {
361         if sig.TypeParams().Len() != 0 {
362                 w.tParamList(sig.TypeParams().list())
363         }
364
365         w.tuple(sig.params, sig.variadic)
366
367         n := sig.results.Len()
368         if n == 0 {
369                 // no result
370                 return
371         }
372
373         w.byte(' ')
374         if n == 1 && (w.env != nil || sig.results.vars[0].name == "") {
375                 // single unnamed result (if type hashing, name must be ignored)
376                 w.typ(sig.results.vars[0].typ)
377                 return
378         }
379
380         // multiple or named result(s)
381         w.tuple(sig.results, false)
382 }
383
384 // subscript returns the decimal (utf8) representation of x using subscript digits.
385 func subscript(x uint64) string {
386         const w = len("₀") // all digits 0...9 have the same utf8 width
387         var buf [32 * w]byte
388         i := len(buf)
389         for {
390                 i -= w
391                 utf8.EncodeRune(buf[i:], '₀'+rune(x%10)) // '₀' == U+2080
392                 x /= 10
393                 if x == 0 {
394                         break
395                 }
396         }
397         return string(buf[i:])
398 }