1
2
3
4
5
6
7 package types2
8
9 import (
10 "bytes"
11 "fmt"
12 "slices"
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 == asNamed(universeComparable.Type()).underlying {
215 w.string("interface{comparable}")
216 break
217 }
218 }
219 if t.implicit {
220 if len(t.methods) == 0 && len(t.embeddeds) == 1 {
221 w.typ(t.embeddeds[0])
222 break
223 }
224
225
226 w.string("/* implicit */ ")
227 }
228 w.string("interface{")
229 first := true
230 if w.ctxt != nil {
231 w.typeSet(t.typeSet())
232 } else {
233 for _, m := range t.methods {
234 if !first {
235 w.byte(';')
236 }
237 first = false
238 w.string(m.name)
239 w.signature(m.typ.(*Signature))
240 }
241 for _, typ := range t.embeddeds {
242 if !first {
243 w.byte(';')
244 }
245 first = false
246 w.typ(typ)
247 }
248 }
249 w.byte('}')
250
251 case *Map:
252 w.string("map[")
253 w.typ(t.key)
254 w.byte(']')
255 w.typ(t.elem)
256
257 case *Chan:
258 var s string
259 var parens bool
260 switch t.dir {
261 case SendRecv:
262 s = "chan "
263
264 if c, _ := t.elem.(*Chan); c != nil && c.dir == RecvOnly {
265 parens = true
266 }
267 case SendOnly:
268 s = "chan<- "
269 case RecvOnly:
270 s = "<-chan "
271 default:
272 w.error("unknown channel direction")
273 }
274 w.string(s)
275 if parens {
276 w.byte('(')
277 }
278 w.typ(t.elem)
279 if parens {
280 w.byte(')')
281 }
282
283 case *Named:
284
285
286 if w.ctxt != nil {
287 w.string(strconv.Itoa(w.ctxt.getID(t)))
288 }
289 w.typeName(t.obj)
290 if t.inst != nil {
291
292 w.typeList(t.inst.targs.list())
293 } else if w.ctxt == nil && t.TypeParams().Len() != 0 {
294
295 w.tParamList(t.TypeParams().list())
296 }
297
298 case *TypeParam:
299 if t.obj == nil {
300 w.error("unnamed type parameter")
301 break
302 }
303 if i := slices.Index(w.tparams.list(), t); i >= 0 {
304
305
306
307 w.string(fmt.Sprintf("$%d", i))
308 } else {
309 w.string(t.obj.name)
310 if w.tpSubscripts || w.ctxt != nil {
311 w.string(subscript(t.id))
312 }
313
314
315
316
317 if w.ctxt == nil && Universe.Lookup(t.obj.name) != nil {
318 if isTypes2 {
319 w.string(fmt.Sprintf(" /* with %s declared at %v */", t.obj.name, t.obj.Pos()))
320 } else {
321
322
323 w.string("/* type parameter */")
324 }
325 }
326 }
327
328 case *Alias:
329 w.typeName(t.obj)
330 if list := t.targs.list(); len(list) != 0 {
331
332 w.typeList(list)
333 } else if w.ctxt == nil && t.TypeParams().Len() != 0 {
334
335 w.tParamList(t.TypeParams().list())
336 }
337 if w.ctxt != nil {
338
339 typ := Unalias(t.obj.typ)
340 if typ == nil {
341 panic("known implementation limitation: encountered an incomplete alias (see go.dev/issue/78296)")
342 }
343 w.typ(typ)
344 }
345
346 default:
347
348
349 w.string(t.String())
350 }
351 }
352
353
354 func (w *typeWriter) typeSet(s *_TypeSet) {
355 assert(w.ctxt != nil)
356 first := true
357 for _, m := range s.methods {
358 if !first {
359 w.byte(';')
360 }
361 first = false
362 w.string(m.name)
363 w.signature(m.typ.(*Signature))
364 }
365 switch {
366 case s.terms.isAll():
367
368 case s.terms.isEmpty():
369 w.string(s.terms.String())
370 default:
371 var termHashes []string
372 for _, term := range s.terms {
373
374 var buf bytes.Buffer
375 if term.tilde {
376 buf.WriteByte('~')
377 }
378 newTypeHasher(&buf, w.ctxt).typ(term.typ)
379 termHashes = append(termHashes, buf.String())
380 }
381 slices.Sort(termHashes)
382 if !first {
383 w.byte(';')
384 }
385 w.string(strings.Join(termHashes, "|"))
386 }
387 }
388
389 func (w *typeWriter) typeList(list []Type) {
390 w.byte('[')
391 for i, typ := range list {
392 if i > 0 {
393 w.byte(',')
394 }
395 w.typ(typ)
396 }
397 w.byte(']')
398 }
399
400 func (w *typeWriter) tParamList(list []*TypeParam) {
401 w.byte('[')
402 var prev Type
403 for i, tpar := range list {
404
405
406
407 if tpar == nil {
408 w.error("nil type parameter")
409 continue
410 }
411 if i > 0 {
412 if tpar.bound != prev {
413
414 w.byte(' ')
415 w.typ(prev)
416 }
417 w.byte(',')
418 }
419 prev = tpar.bound
420 w.typ(tpar)
421 }
422 if prev != nil {
423 w.byte(' ')
424 w.typ(prev)
425 }
426 w.byte(']')
427 }
428
429 func (w *typeWriter) typeName(obj *TypeName) {
430 w.string(packagePrefix(obj.pkg, w.qf))
431 w.string(obj.name)
432 }
433
434 func (w *typeWriter) tuple(tup *Tuple, variadic bool) {
435 w.byte('(')
436 if tup != nil {
437 for i, v := range tup.vars {
438 if i > 0 {
439 w.byte(',')
440 }
441
442 if w.ctxt == nil && v.name != "" && w.paramNames {
443 w.string(v.name)
444 w.byte(' ')
445 }
446 typ := v.typ
447 if variadic && i == len(tup.vars)-1 {
448 if slice, ok := typ.(*Slice); ok {
449 w.string("...")
450 w.typ(slice.elem)
451 } else {
452
453
454
455
456
457
458
459
460
461 w.typ(typ)
462 w.string("...")
463 }
464 } else {
465 w.typ(typ)
466 }
467 }
468 }
469 w.byte(')')
470 }
471
472 func (w *typeWriter) signature(sig *Signature) {
473 if sig.TypeParams().Len() != 0 {
474 if w.ctxt != nil {
475 assert(w.tparams == nil)
476 w.tparams = sig.TypeParams()
477 defer func() {
478 w.tparams = nil
479 }()
480 }
481 w.tParamList(sig.TypeParams().list())
482 }
483
484 w.tuple(sig.params, sig.variadic)
485
486 n := sig.results.Len()
487 if n == 0 {
488
489 return
490 }
491
492 w.byte(' ')
493 if n == 1 && (w.ctxt != nil || sig.results.vars[0].name == "") {
494
495 w.typ(sig.results.vars[0].typ)
496 return
497 }
498
499
500 w.tuple(sig.results, false)
501 }
502
503
504 func subscript(x uint64) string {
505 const w = len("₀")
506 var buf [32 * w]byte
507 i := len(buf)
508 for {
509 i -= w
510 utf8.EncodeRune(buf[i:], '₀'+rune(x%10))
511 x /= 10
512 if x == 0 {
513 break
514 }
515 }
516 return string(buf[i:])
517 }
518
View as plain text