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