Source file src/pkg/go/types/typestring.go
1
2
3
4
5
6
7 package types
8
9 import (
10 "bytes"
11 "fmt"
12 )
13
14
15
16
17
18
19
20
21
22
23
24
25 type Qualifier func(*Package) string
26
27
28
29 func RelativeTo(pkg *Package) Qualifier {
30 if pkg == nil {
31 return nil
32 }
33 return func(other *Package) string {
34 if pkg == other {
35 return ""
36 }
37 return other.Path()
38 }
39 }
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60 var gcCompatibilityMode bool
61
62
63
64
65 func TypeString(typ Type, qf Qualifier) string {
66 var buf bytes.Buffer
67 WriteType(&buf, typ, qf)
68 return buf.String()
69 }
70
71
72
73
74 func WriteType(buf *bytes.Buffer, typ Type, qf Qualifier) {
75 writeType(buf, typ, qf, make([]Type, 0, 8))
76 }
77
78 func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) {
79
80
81
82
83 for _, t := range visited {
84 if t == typ {
85 fmt.Fprintf(buf, "○%T", typ)
86 return
87 }
88 }
89 visited = append(visited, typ)
90
91 switch t := typ.(type) {
92 case nil:
93 buf.WriteString("<nil>")
94
95 case *Basic:
96 if t.kind == UnsafePointer {
97 buf.WriteString("unsafe.")
98 }
99 if gcCompatibilityMode {
100
101 switch t.kind {
102 case Byte:
103 t = Typ[Uint8]
104 case Rune:
105 t = Typ[Int32]
106 }
107 }
108 buf.WriteString(t.name)
109
110 case *Array:
111 fmt.Fprintf(buf, "[%d]", t.len)
112 writeType(buf, t.elem, qf, visited)
113
114 case *Slice:
115 buf.WriteString("[]")
116 writeType(buf, t.elem, qf, visited)
117
118 case *Struct:
119 buf.WriteString("struct{")
120 for i, f := range t.fields {
121 if i > 0 {
122 buf.WriteString("; ")
123 }
124 if !f.embedded {
125 buf.WriteString(f.name)
126 buf.WriteByte(' ')
127 }
128 writeType(buf, f.typ, qf, visited)
129 if tag := t.Tag(i); tag != "" {
130 fmt.Fprintf(buf, " %q", tag)
131 }
132 }
133 buf.WriteByte('}')
134
135 case *Pointer:
136 buf.WriteByte('*')
137 writeType(buf, t.base, qf, visited)
138
139 case *Tuple:
140 writeTuple(buf, t, false, qf, visited)
141
142 case *Signature:
143 buf.WriteString("func")
144 writeSignature(buf, t, qf, visited)
145
146 case *Interface:
147
148
149
150
151
152
153
154
155
156
157
158 buf.WriteString("interface{")
159 empty := true
160 if gcCompatibilityMode {
161
162
163 for i, m := range t.allMethods {
164 if i > 0 {
165 buf.WriteString("; ")
166 }
167 buf.WriteString(m.name)
168 writeSignature(buf, m.typ.(*Signature), qf, visited)
169 empty = false
170 }
171 } else {
172
173 for i, m := range t.methods {
174 if i > 0 {
175 buf.WriteString("; ")
176 }
177 buf.WriteString(m.name)
178 writeSignature(buf, m.typ.(*Signature), qf, visited)
179 empty = false
180 }
181 for i, typ := range t.embeddeds {
182 if i > 0 || len(t.methods) > 0 {
183 buf.WriteString("; ")
184 }
185 writeType(buf, typ, qf, visited)
186 empty = false
187 }
188 }
189 if t.allMethods == nil || len(t.methods) > len(t.allMethods) {
190 if !empty {
191 buf.WriteByte(' ')
192 }
193 buf.WriteString("/* incomplete */")
194 }
195 buf.WriteByte('}')
196
197 case *Map:
198 buf.WriteString("map[")
199 writeType(buf, t.key, qf, visited)
200 buf.WriteByte(']')
201 writeType(buf, t.elem, qf, visited)
202
203 case *Chan:
204 var s string
205 var parens bool
206 switch t.dir {
207 case SendRecv:
208 s = "chan "
209
210 if c, _ := t.elem.(*Chan); c != nil && c.dir == RecvOnly {
211 parens = true
212 }
213 case SendOnly:
214 s = "chan<- "
215 case RecvOnly:
216 s = "<-chan "
217 default:
218 panic("unreachable")
219 }
220 buf.WriteString(s)
221 if parens {
222 buf.WriteByte('(')
223 }
224 writeType(buf, t.elem, qf, visited)
225 if parens {
226 buf.WriteByte(')')
227 }
228
229 case *Named:
230 s := "<Named w/o object>"
231 if obj := t.obj; obj != nil {
232 if obj.pkg != nil {
233 writePackage(buf, obj.pkg, qf)
234 }
235
236
237
238 s = obj.name
239 }
240 buf.WriteString(s)
241
242 default:
243
244 buf.WriteString(t.String())
245 }
246 }
247
248 func writeTuple(buf *bytes.Buffer, tup *Tuple, variadic bool, qf Qualifier, visited []Type) {
249 buf.WriteByte('(')
250 if tup != nil {
251 for i, v := range tup.vars {
252 if i > 0 {
253 buf.WriteString(", ")
254 }
255 if v.name != "" {
256 buf.WriteString(v.name)
257 buf.WriteByte(' ')
258 }
259 typ := v.typ
260 if variadic && i == len(tup.vars)-1 {
261 if s, ok := typ.(*Slice); ok {
262 buf.WriteString("...")
263 typ = s.elem
264 } else {
265
266
267 if t, ok := typ.Underlying().(*Basic); !ok || t.kind != String {
268 panic("internal error: string type expected")
269 }
270 writeType(buf, typ, qf, visited)
271 buf.WriteString("...")
272 continue
273 }
274 }
275 writeType(buf, typ, qf, visited)
276 }
277 }
278 buf.WriteByte(')')
279 }
280
281
282
283
284
285 func WriteSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier) {
286 writeSignature(buf, sig, qf, make([]Type, 0, 8))
287 }
288
289 func writeSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier, visited []Type) {
290 writeTuple(buf, sig.params, sig.variadic, qf, visited)
291
292 n := sig.results.Len()
293 if n == 0 {
294
295 return
296 }
297
298 buf.WriteByte(' ')
299 if n == 1 && sig.results.vars[0].name == "" {
300
301 writeType(buf, sig.results.vars[0].typ, qf, visited)
302 return
303 }
304
305
306 writeTuple(buf, sig.results, false, qf, visited)
307 }
308
View as plain text