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