]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/types2/typestring.go
cmd/compile: fix deadlock in (*Named).load
[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                 }
216                 w.string(s)
217                 if parens {
218                         w.byte('(')
219                 }
220                 w.typ(t.elem)
221                 if parens {
222                         w.byte(')')
223                 }
224
225         case *Named:
226                 // Instance markers indicate unexpanded instantiated
227                 // types. Write them to aid debugging, but don't write
228                 // them when we need an instance hash: whether a type
229                 // is fully expanded or not doesn't matter for identity.
230                 if !w.hash && t.instPos != nil {
231                         w.byte(instanceMarker)
232                 }
233                 w.typeName(t.obj)
234                 if t.targs != nil {
235                         // instantiated type
236                         w.typeList(t.targs.list())
237                 } else if !w.hash && t.TParams().Len() != 0 { // For type hashing, don't need to format the TParams
238                         // parameterized type
239                         w.tParamList(t.TParams().list())
240                 }
241
242         case *TypeParam:
243                 if t.obj == nil {
244                         w.error("unnamed type parameter")
245                         break
246                 }
247                 // Optionally write out package for typeparams (like Named).
248                 // TODO(danscales): this is required for import/export, so
249                 // we maybe need a separate function that won't be changed
250                 // for debugging purposes.
251                 if t.obj.pkg != nil {
252                         writePackage(w.buf, t.obj.pkg, w.qf)
253                 }
254                 w.string(t.obj.name + subscript(t.id))
255
256         case *top:
257                 w.error("⊤")
258
259         default:
260                 // For externally defined implementations of Type.
261                 // Note: In this case cycles won't be caught.
262                 w.string(t.String())
263         }
264 }
265
266 func (w *typeWriter) typeList(list []Type) {
267         w.byte('[')
268         for i, typ := range list {
269                 if i > 0 {
270                         w.string(", ")
271                 }
272                 w.typ(typ)
273         }
274         w.byte(']')
275 }
276
277 func (w *typeWriter) tParamList(list []*TypeParam) {
278         w.byte('[')
279         var prev Type
280         for i, tpar := range list {
281                 // Determine the type parameter and its constraint.
282                 // list is expected to hold type parameter names,
283                 // but don't crash if that's not the case.
284                 if tpar == nil {
285                         w.error("nil type parameter")
286                         continue
287                 }
288                 if i > 0 {
289                         if tpar.bound != prev {
290                                 // bound changed - write previous one before advancing
291                                 w.byte(' ')
292                                 w.typ(prev)
293                         }
294                         w.string(", ")
295                 }
296                 prev = tpar.bound
297                 w.typ(tpar)
298         }
299         if prev != nil {
300                 w.byte(' ')
301                 w.typ(prev)
302         }
303         w.byte(']')
304 }
305
306 func (w *typeWriter) typeName(obj *TypeName) {
307         if obj.pkg != nil {
308                 writePackage(w.buf, obj.pkg, w.qf)
309         }
310         w.string(obj.name)
311
312         if w.hash {
313                 // For local defined types, use the (original!) TypeName's scope
314                 // numbers to disambiguate.
315                 if typ, _ := obj.typ.(*Named); typ != nil {
316                         // TODO(gri) Figure out why typ.orig != typ.orig.orig sometimes
317                         //           and whether the loop can iterate more than twice.
318                         //           (It seems somehow connected to instance types.)
319                         for typ.orig != typ {
320                                 typ = typ.orig
321                         }
322                         w.writeScopeNumbers(typ.obj.parent)
323                 }
324         }
325 }
326
327 // writeScopeNumbers writes the number sequence for this scope to buf
328 // in the form ".i.j.k" where i, j, k, etc. stand for scope numbers.
329 // If a scope is nil or has no parent (such as a package scope), nothing
330 // is written.
331 func (w *typeWriter) writeScopeNumbers(s *Scope) {
332         if s != nil && s.number > 0 {
333                 w.writeScopeNumbers(s.parent)
334                 w.writef(".%d", s.number)
335         }
336 }
337
338 func (w *typeWriter) tuple(tup *Tuple, variadic bool) {
339         w.byte('(')
340         if tup != nil {
341                 for i, v := range tup.vars {
342                         if i > 0 {
343                                 w.string(", ")
344                         }
345                         // parameter names are ignored for type identity and thus type hashes
346                         if !w.hash && v.name != "" {
347                                 w.string(v.name)
348                                 w.byte(' ')
349                         }
350                         typ := v.typ
351                         if variadic && i == len(tup.vars)-1 {
352                                 if s, ok := typ.(*Slice); ok {
353                                         w.string("...")
354                                         typ = s.elem
355                                 } else {
356                                         // special case:
357                                         // append(s, "foo"...) leads to signature func([]byte, string...)
358                                         if t := asBasic(typ); t == nil || t.kind != String {
359                                                 w.error("expected string type")
360                                                 continue
361                                         }
362                                         w.typ(typ)
363                                         w.string("...")
364                                         continue
365                                 }
366                         }
367                         w.typ(typ)
368                 }
369         }
370         w.byte(')')
371 }
372
373 func (w *typeWriter) signature(sig *Signature) {
374         if sig.TParams().Len() != 0 {
375                 w.tParamList(sig.TParams().list())
376         }
377
378         w.tuple(sig.params, sig.variadic)
379
380         n := sig.results.Len()
381         if n == 0 {
382                 // no result
383                 return
384         }
385
386         w.byte(' ')
387         if n == 1 && (w.hash || sig.results.vars[0].name == "") {
388                 // single unnamed result (if type hashing, name must be ignored)
389                 w.typ(sig.results.vars[0].typ)
390                 return
391         }
392
393         // multiple or named result(s)
394         w.tuple(sig.results, false)
395 }
396
397 // subscript returns the decimal (utf8) representation of x using subscript digits.
398 func subscript(x uint64) string {
399         const w = len("₀") // all digits 0...9 have the same utf8 width
400         var buf [32 * w]byte
401         i := len(buf)
402         for {
403                 i -= w
404                 utf8.EncodeRune(buf[i:], '₀'+rune(x%10)) // '₀' == U+2080
405                 x /= 10
406                 if x == 0 {
407                         break
408                 }
409         }
410         return string(buf[i:])
411 }