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