Source file
src/go/types/typestring.go
1
2
3
4
5
6
7 package types
8
9 import (
10 "bytes"
11 "fmt"
12 "go/token"
13 "unicode/utf8"
14 )
15
16
17
18
19
20
21
22
23
24
25
26
27 type Qualifier func(*Package) string
28
29
30
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 ""
38 }
39 return other.Path()
40 }
41 }
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62 var gcCompatibilityMode bool
63
64
65
66
67 func TypeString(typ Type, qf Qualifier) string {
68 var buf bytes.Buffer
69 WriteType(&buf, typ, qf)
70 return buf.String()
71 }
72
73
74
75
76 func WriteType(buf *bytes.Buffer, typ Type, qf Qualifier) {
77 writeType(buf, typ, qf, make([]Type, 0, 8))
78 }
79
80
81
82 const instanceMarker = '#'
83
84 func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) {
85
86
87
88
89 for _, t := range visited {
90 if t == typ {
91 fmt.Fprintf(buf, "○%T", goTypeName(typ))
92 return
93 }
94 }
95 visited = append(visited, typ)
96
97 switch t := typ.(type) {
98 case nil:
99 buf.WriteString("<nil>")
100
101 case *Basic:
102
103
104 if token.IsExported(t.name) {
105 if obj, _ := Unsafe.scope.Lookup(t.name).(*TypeName); obj != nil {
106 writeTypeName(buf, obj, qf)
107 break
108 }
109 }
110
111 if gcCompatibilityMode {
112
113 switch t.kind {
114 case Byte:
115 t = Typ[Uint8]
116 case Rune:
117 t = Typ[Int32]
118 }
119 }
120 buf.WriteString(t.name)
121
122 case *Array:
123 fmt.Fprintf(buf, "[%d]", t.len)
124 writeType(buf, t.elem, qf, visited)
125
126 case *Slice:
127 buf.WriteString("[]")
128 writeType(buf, t.elem, qf, visited)
129
130 case *Struct:
131 buf.WriteString("struct{")
132 for i, f := range t.fields {
133 if i > 0 {
134 buf.WriteString("; ")
135 }
136
137
138
139 if !f.embedded {
140 buf.WriteString(f.name)
141 buf.WriteByte(' ')
142 }
143 writeType(buf, f.typ, qf, visited)
144 if tag := t.Tag(i); tag != "" {
145 fmt.Fprintf(buf, " %q", tag)
146 }
147 }
148 buf.WriteByte('}')
149
150 case *Pointer:
151 buf.WriteByte('*')
152 writeType(buf, t.base, qf, visited)
153
154 case *Tuple:
155 writeTuple(buf, t, false, qf, visited)
156
157 case *Signature:
158 buf.WriteString("func")
159 writeSignature(buf, t, qf, visited)
160
161 case *_Sum:
162 for i, t := range t.types {
163 if i > 0 {
164 buf.WriteString(", ")
165 }
166 writeType(buf, t, qf, visited)
167 }
168
169 case *Interface:
170
171
172
173
174
175
176
177
178
179
180
181 buf.WriteString("interface{")
182 empty := true
183 if gcCompatibilityMode {
184
185
186 for i, m := range t.allMethods {
187 if i > 0 {
188 buf.WriteString("; ")
189 }
190 buf.WriteString(m.name)
191 writeSignature(buf, m.typ.(*Signature), qf, visited)
192 empty = false
193 }
194 if !empty && t.allTypes != nil {
195 buf.WriteString("; ")
196 }
197 if t.allTypes != nil {
198 buf.WriteString("type ")
199 writeType(buf, t.allTypes, qf, visited)
200 }
201 } else {
202
203 for i, m := range t.methods {
204 if i > 0 {
205 buf.WriteString("; ")
206 }
207 buf.WriteString(m.name)
208 writeSignature(buf, m.typ.(*Signature), qf, visited)
209 empty = false
210 }
211 if !empty && t.types != nil {
212 buf.WriteString("; ")
213 }
214 if t.types != nil {
215 buf.WriteString("type ")
216 writeType(buf, t.types, qf, visited)
217 empty = false
218 }
219 if !empty && len(t.embeddeds) > 0 {
220 buf.WriteString("; ")
221 }
222 for i, typ := range t.embeddeds {
223 if i > 0 {
224 buf.WriteString("; ")
225 }
226 writeType(buf, typ, qf, visited)
227 empty = false
228 }
229 }
230 if t.allMethods == nil || len(t.methods) > len(t.allMethods) {
231 if !empty {
232 buf.WriteByte(' ')
233 }
234 buf.WriteString("/* incomplete */")
235 }
236 buf.WriteByte('}')
237
238 case *Map:
239 buf.WriteString("map[")
240 writeType(buf, t.key, qf, visited)
241 buf.WriteByte(']')
242 writeType(buf, t.elem, qf, visited)
243
244 case *Chan:
245 var s string
246 var parens bool
247 switch t.dir {
248 case SendRecv:
249 s = "chan "
250
251 if c, _ := t.elem.(*Chan); c != nil && c.dir == RecvOnly {
252 parens = true
253 }
254 case SendOnly:
255 s = "chan<- "
256 case RecvOnly:
257 s = "<-chan "
258 default:
259 panic("unreachable")
260 }
261 buf.WriteString(s)
262 if parens {
263 buf.WriteByte('(')
264 }
265 writeType(buf, t.elem, qf, visited)
266 if parens {
267 buf.WriteByte(')')
268 }
269
270 case *Named:
271 writeTypeName(buf, t.obj, qf)
272 if t.targs != nil {
273
274 buf.WriteByte('[')
275 writeTypeList(buf, t.targs, qf, visited)
276 buf.WriteByte(']')
277 } else if t.tparams != nil {
278
279 writeTParamList(buf, t.tparams, qf, visited)
280 }
281
282 case *_TypeParam:
283 s := "?"
284 if t.obj != nil {
285 s = t.obj.name
286 }
287 buf.WriteString(s + subscript(t.id))
288
289 case *instance:
290 buf.WriteByte(instanceMarker)
291 writeTypeName(buf, t.base.obj, qf)
292 buf.WriteByte('[')
293 writeTypeList(buf, t.targs, qf, visited)
294 buf.WriteByte(']')
295
296 case *bottom:
297 buf.WriteString("⊥")
298
299 case *top:
300 buf.WriteString("⊤")
301
302 default:
303
304 buf.WriteString(t.String())
305 }
306 }
307
308 func writeTypeList(buf *bytes.Buffer, list []Type, qf Qualifier, visited []Type) {
309 for i, typ := range list {
310 if i > 0 {
311 buf.WriteString(", ")
312 }
313 writeType(buf, typ, qf, visited)
314 }
315 }
316
317 func writeTParamList(buf *bytes.Buffer, list []*TypeName, qf Qualifier, visited []Type) {
318
319 buf.WriteString("[")
320 var prev Type
321 for i, p := range list {
322
323 var b Type = &emptyInterface
324 if t, _ := p.typ.(*_TypeParam); t != nil && t.bound != nil {
325 b = t.bound
326 }
327 if i > 0 {
328 if b != prev {
329
330 buf.WriteByte(' ')
331 writeType(buf, prev, qf, visited)
332 }
333 buf.WriteString(", ")
334 }
335 prev = b
336
337 if t, _ := p.typ.(*_TypeParam); t != nil {
338 writeType(buf, t, qf, visited)
339 } else {
340 buf.WriteString(p.name)
341 }
342 }
343 if prev != nil {
344 buf.WriteByte(' ')
345 writeType(buf, prev, qf, visited)
346 }
347 buf.WriteByte(']')
348 }
349
350 func writeTypeName(buf *bytes.Buffer, obj *TypeName, qf Qualifier) {
351 s := "<Named w/o object>"
352 if obj != nil {
353 if obj.pkg != nil {
354 writePackage(buf, obj.pkg, qf)
355 }
356
357
358
359 s = obj.name
360 }
361 buf.WriteString(s)
362 }
363
364 func writeTuple(buf *bytes.Buffer, tup *Tuple, variadic bool, qf Qualifier, visited []Type) {
365 buf.WriteByte('(')
366 if tup != nil {
367 for i, v := range tup.vars {
368 if i > 0 {
369 buf.WriteString(", ")
370 }
371 if v.name != "" {
372 buf.WriteString(v.name)
373 buf.WriteByte(' ')
374 }
375 typ := v.typ
376 if variadic && i == len(tup.vars)-1 {
377 if s, ok := typ.(*Slice); ok {
378 buf.WriteString("...")
379 typ = s.elem
380 } else {
381
382
383 if t := asBasic(typ); t == nil || t.kind != String {
384 panic("internal error: string type expected")
385 }
386 writeType(buf, typ, qf, visited)
387 buf.WriteString("...")
388 continue
389 }
390 }
391 writeType(buf, typ, qf, visited)
392 }
393 }
394 buf.WriteByte(')')
395 }
396
397
398
399
400
401 func WriteSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier) {
402 writeSignature(buf, sig, qf, make([]Type, 0, 8))
403 }
404
405 func writeSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier, visited []Type) {
406 if sig.tparams != nil {
407 writeTParamList(buf, sig.tparams, qf, visited)
408 }
409
410 writeTuple(buf, sig.params, sig.variadic, qf, visited)
411
412 n := sig.results.Len()
413 if n == 0 {
414
415 return
416 }
417
418 buf.WriteByte(' ')
419 if n == 1 && sig.results.vars[0].name == "" {
420
421 writeType(buf, sig.results.vars[0].typ, qf, visited)
422 return
423 }
424
425
426 writeTuple(buf, sig.results, false, qf, visited)
427 }
428
429
430 func subscript(x uint64) string {
431 const w = len("₀")
432 var buf [32 * w]byte
433 i := len(buf)
434 for {
435 i -= w
436 utf8.EncodeRune(buf[i:], '₀'+rune(x%10))
437 x /= 10
438 if x == 0 {
439 break
440 }
441 }
442 return string(buf[i:])
443 }
444
View as plain text