1
2
3
4
5
6
7 package types2
8
9 import (
10 "bytes"
11 "fmt"
12 "sort"
13 "strconv"
14 "strings"
15 "unicode/utf8"
16 )
17
18
19
20
21
22
23
24
25
26
27
28 type Qualifier func(*Package) string
29
30
31
32 func RelativeTo(pkg *Package) Qualifier {
33 if pkg == nil {
34 return nil
35 }
36 return func(other *Package) string {
37 if pkg == other {
38 return ""
39 }
40 return other.Path()
41 }
42 }
43
44
45
46
47 func TypeString(typ Type, qf Qualifier) string {
48 var buf bytes.Buffer
49 WriteType(&buf, typ, qf)
50 return buf.String()
51 }
52
53
54
55
56 func WriteType(buf *bytes.Buffer, typ Type, qf Qualifier) {
57 newTypeWriter(buf, qf).typ(typ)
58 }
59
60
61
62
63 func WriteSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier) {
64 newTypeWriter(buf, qf).signature(sig)
65 }
66
67 type typeWriter struct {
68 buf *bytes.Buffer
69 seen map[Type]bool
70 qf Qualifier
71 ctxt *Context
72 tparams *TypeParamList
73 paramNames bool
74 tpSubscripts bool
75 pkgInfo bool
76 }
77
78 func newTypeWriter(buf *bytes.Buffer, qf Qualifier) *typeWriter {
79 return &typeWriter{buf, make(map[Type]bool), qf, nil, nil, true, false, false}
80 }
81
82 func newTypeHasher(buf *bytes.Buffer, ctxt *Context) *typeWriter {
83 assert(ctxt != nil)
84 return &typeWriter{buf, make(map[Type]bool), nil, ctxt, nil, false, false, false}
85 }
86
87 func (w *typeWriter) byte(b byte) {
88 if w.ctxt != nil {
89 if b == ' ' {
90 b = '#'
91 }
92 w.buf.WriteByte(b)
93 return
94 }
95 w.buf.WriteByte(b)
96 if b == ',' || b == ';' {
97 w.buf.WriteByte(' ')
98 }
99 }
100
101 func (w *typeWriter) string(s string) {
102 w.buf.WriteString(s)
103 }
104
105 func (w *typeWriter) error(msg string) {
106 if w.ctxt != nil {
107 panic(msg)
108 }
109 w.buf.WriteString("<" + msg + ">")
110 }
111
112 func (w *typeWriter) typ(typ Type) {
113 if w.seen[typ] {
114 w.error("cycle to " + goTypeName(typ))
115 return
116 }
117 w.seen[typ] = true
118 defer delete(w.seen, typ)
119
120 switch t := typ.(type) {
121 case nil:
122 w.error("nil")
123
124 case *Basic:
125
126
127 if isExported(t.name) {
128 if obj, _ := Unsafe.scope.Lookup(t.name).(*TypeName); obj != nil {
129 w.typeName(obj)
130 break
131 }
132 }
133 w.string(t.name)
134
135 case *Array:
136 w.byte('[')
137 w.string(strconv.FormatInt(t.len, 10))
138 w.byte(']')
139 w.typ(t.elem)
140
141 case *Slice:
142 w.string("[]")
143 w.typ(t.elem)
144
145 case *Struct:
146 w.string("struct{")
147 for i, f := range t.fields {
148 if i > 0 {
149 w.byte(';')
150 }
151
152
153
154 pkgAnnotate := false
155 if w.qf == nil && w.pkgInfo && !isExported(f.name) {
156
157 pkgAnnotate = true
158 w.pkgInfo = false
159 }
160
161
162
163
164 if !f.embedded {
165 w.string(f.name)
166 w.byte(' ')
167 }
168 w.typ(f.typ)
169 if pkgAnnotate {
170 w.string(" /* package ")
171 w.string(f.pkg.Path())
172 w.string(" */ ")
173 }
174 if tag := t.Tag(i); tag != "" {
175 w.byte(' ')
176
177
178
179 w.string(strconv.Quote(tag))
180 }
181 }
182 w.byte('}')
183
184 case *Pointer:
185 w.byte('*')
186 w.typ(t.base)
187
188 case *Tuple:
189 w.tuple(t, false)
190
191 case *Signature:
192 w.string("func")
193 w.signature(t)
194
195 case *Union:
196
197
198 if t.Len() == 0 {
199 w.error("empty union")
200 break
201 }
202 for i, t := range t.terms {
203 if i > 0 {
204 w.string(termSep)
205 }
206 if t.tilde {
207 w.byte('~')
208 }
209 w.typ(t.typ)
210 }
211
212 case *Interface:
213 if w.ctxt == nil {
214 if t == universeAny.Type() {
215
216
217
218 w.string("any")
219 break
220 }
221 if t == asNamed(universeComparable.Type()).underlying {
222 w.string("interface{comparable}")
223 break
224 }
225 }
226 if t.implicit {
227 if len(t.methods) == 0 && len(t.embeddeds) == 1 {
228 w.typ(t.embeddeds[0])
229 break
230 }
231
232
233 w.string("/* implicit */ ")
234 }
235 w.string("interface{")
236 first := true
237 if w.ctxt != nil {
238 w.typeSet(t.typeSet())
239 } else {
240 for _, m := range t.methods {
241 if !first {
242 w.byte(';')
243 }
244 first = false
245 w.string(m.name)
246 w.signature(m.typ.(*Signature))
247 }
248 for _, typ := range t.embeddeds {
249 if !first {
250 w.byte(';')
251 }
252 first = false
253 w.typ(typ)
254 }
255 }
256 w.byte('}')
257
258 case *Map:
259 w.string("map[")
260 w.typ(t.key)
261 w.byte(']')
262 w.typ(t.elem)
263
264 case *Chan:
265 var s string
266 var parens bool
267 switch t.dir {
268 case SendRecv:
269 s = "chan "
270
271 if c, _ := t.elem.(*Chan); c != nil && c.dir == RecvOnly {
272 parens = true
273 }
274 case SendOnly:
275 s = "chan<- "
276 case RecvOnly:
277 s = "<-chan "
278 default:
279 w.error("unknown channel direction")
280 }
281 w.string(s)
282 if parens {
283 w.byte('(')
284 }
285 w.typ(t.elem)
286 if parens {
287 w.byte(')')
288 }
289
290 case *Named:
291
292
293 if w.ctxt != nil {
294 w.string(strconv.Itoa(w.ctxt.getID(t)))
295 }
296 w.typeName(t.obj)
297 if t.inst != nil {
298
299 w.typeList(t.inst.targs.list())
300 } else if w.ctxt == nil && t.TypeParams().Len() != 0 {
301
302 w.tParamList(t.TypeParams().list())
303 }
304
305 case *TypeParam:
306 if t.obj == nil {
307 w.error("unnamed type parameter")
308 break
309 }
310 if i := tparamIndex(w.tparams.list(), t); i >= 0 {
311
312
313
314 w.string(fmt.Sprintf("$%d", i))
315 } else {
316 w.string(t.obj.name)
317 if w.tpSubscripts || w.ctxt != nil {
318 w.string(subscript(t.id))
319 }
320
321
322
323
324 if w.ctxt == nil && Universe.Lookup(t.obj.name) != nil {
325 w.string(fmt.Sprintf(" /* with %s declared at %s */", t.obj.name, t.obj.Pos()))
326 }
327 }
328
329 case *Alias:
330 w.typeName(t.obj)
331 if w.ctxt != nil {
332
333 w.typ(Unalias(t.obj.typ))
334 }
335
336 default:
337
338
339 w.string(t.String())
340 }
341 }
342
343
344 func (w *typeWriter) typeSet(s *_TypeSet) {
345 assert(w.ctxt != nil)
346 first := true
347 for _, m := range s.methods {
348 if !first {
349 w.byte(';')
350 }
351 first = false
352 w.string(m.name)
353 w.signature(m.typ.(*Signature))
354 }
355 switch {
356 case s.terms.isAll():
357
358 case s.terms.isEmpty():
359 w.string(s.terms.String())
360 default:
361 var termHashes []string
362 for _, term := range s.terms {
363
364 var buf bytes.Buffer
365 if term.tilde {
366 buf.WriteByte('~')
367 }
368 newTypeHasher(&buf, w.ctxt).typ(term.typ)
369 termHashes = append(termHashes, buf.String())
370 }
371 sort.Strings(termHashes)
372 if !first {
373 w.byte(';')
374 }
375 w.string(strings.Join(termHashes, "|"))
376 }
377 }
378
379 func (w *typeWriter) typeList(list []Type) {
380 w.byte('[')
381 for i, typ := range list {
382 if i > 0 {
383 w.byte(',')
384 }
385 w.typ(typ)
386 }
387 w.byte(']')
388 }
389
390 func (w *typeWriter) tParamList(list []*TypeParam) {
391 w.byte('[')
392 var prev Type
393 for i, tpar := range list {
394
395
396
397 if tpar == nil {
398 w.error("nil type parameter")
399 continue
400 }
401 if i > 0 {
402 if tpar.bound != prev {
403
404 w.byte(' ')
405 w.typ(prev)
406 }
407 w.byte(',')
408 }
409 prev = tpar.bound
410 w.typ(tpar)
411 }
412 if prev != nil {
413 w.byte(' ')
414 w.typ(prev)
415 }
416 w.byte(']')
417 }
418
419 func (w *typeWriter) typeName(obj *TypeName) {
420 w.string(packagePrefix(obj.pkg, w.qf))
421 w.string(obj.name)
422 }
423
424 func (w *typeWriter) tuple(tup *Tuple, variadic bool) {
425 w.byte('(')
426 if tup != nil {
427 for i, v := range tup.vars {
428 if i > 0 {
429 w.byte(',')
430 }
431
432 if w.ctxt == nil && v.name != "" && w.paramNames {
433 w.string(v.name)
434 w.byte(' ')
435 }
436 typ := v.typ
437 if variadic && i == len(tup.vars)-1 {
438 if s, ok := typ.(*Slice); ok {
439 w.string("...")
440 typ = s.elem
441 } else {
442
443
444 if t, _ := under(typ).(*Basic); t == nil || t.kind != String {
445 w.error("expected string type")
446 continue
447 }
448 w.typ(typ)
449 w.string("...")
450 continue
451 }
452 }
453 w.typ(typ)
454 }
455 }
456 w.byte(')')
457 }
458
459 func (w *typeWriter) signature(sig *Signature) {
460 if sig.TypeParams().Len() != 0 {
461 if w.ctxt != nil {
462 assert(w.tparams == nil)
463 w.tparams = sig.TypeParams()
464 defer func() {
465 w.tparams = nil
466 }()
467 }
468 w.tParamList(sig.TypeParams().list())
469 }
470
471 w.tuple(sig.params, sig.variadic)
472
473 n := sig.results.Len()
474 if n == 0 {
475
476 return
477 }
478
479 w.byte(' ')
480 if n == 1 && (w.ctxt != nil || sig.results.vars[0].name == "") {
481
482 w.typ(sig.results.vars[0].typ)
483 return
484 }
485
486
487 w.tuple(sig.results, false)
488 }
489
490
491 func subscript(x uint64) string {
492 const w = len("₀")
493 var buf [32 * w]byte
494 i := len(buf)
495 for {
496 i -= w
497 utf8.EncodeRune(buf[i:], '₀'+rune(x%10))
498 x /= 10
499 if x == 0 {
500 break
501 }
502 }
503 return string(buf[i:])
504 }
505
View as plain text