libgo: update to Go 1.11
[official-gcc.git] / libgo / go / go / types / typestring.go
blob0c007f6cd0155157af9d018004ee84d3968a2038
1 // Copyright 2013 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // This file implements printing of types.
7 package types
9 import (
10 "bytes"
11 "fmt"
14 // A Qualifier controls how named package-level objects are printed in
15 // calls to TypeString, ObjectString, and SelectionString.
17 // These three formatting routines call the Qualifier for each
18 // package-level object O, and if the Qualifier returns a non-empty
19 // string p, the object is printed in the form p.O.
20 // If it returns an empty string, only the object name O is printed.
22 // Using a nil Qualifier is equivalent to using (*Package).Path: the
23 // object is qualified by the import path, e.g., "encoding/json.Marshal".
25 type Qualifier func(*Package) string
27 // RelativeTo(pkg) returns a Qualifier that fully qualifies members of
28 // all packages other than pkg.
29 func RelativeTo(pkg *Package) Qualifier {
30 if pkg == nil {
31 return nil
33 return func(other *Package) string {
34 if pkg == other {
35 return "" // same package; unqualified
37 return other.Path()
41 // If gcCompatibilityMode is set, printing of types is modified
42 // to match the representation of some types in the gc compiler:
44 // - byte and rune lose their alias name and simply stand for
45 // uint8 and int32 respectively
46 // - embedded interfaces get flattened (the embedding info is lost,
47 // and certain recursive interface types cannot be printed anymore)
49 // This makes it easier to compare packages computed with the type-
50 // checker vs packages imported from gc export data.
52 // Caution: This flag affects all uses of WriteType, globally.
53 // It is only provided for testing in conjunction with
54 // gc-generated data.
56 // This flag is exported in the x/tools/go/types package. We don't
57 // need it at the moment in the std repo and so we don't export it
58 // anymore. We should eventually try to remove it altogether.
59 // TODO(gri) remove this
60 var gcCompatibilityMode bool
62 // TypeString returns the string representation of typ.
63 // The Qualifier controls the printing of
64 // package-level objects, and may be nil.
65 func TypeString(typ Type, qf Qualifier) string {
66 var buf bytes.Buffer
67 WriteType(&buf, typ, qf)
68 return buf.String()
71 // WriteType writes the string representation of typ to buf.
72 // The Qualifier controls the printing of
73 // package-level objects, and may be nil.
74 func WriteType(buf *bytes.Buffer, typ Type, qf Qualifier) {
75 writeType(buf, typ, qf, make([]Type, 0, 8))
78 func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) {
79 // Theoretically, this is a quadratic lookup algorithm, but in
80 // practice deeply nested composite types with unnamed component
81 // types are uncommon. This code is likely more efficient than
82 // using a map.
83 for _, t := range visited {
84 if t == typ {
85 fmt.Fprintf(buf, "○%T", typ) // cycle to typ
86 return
89 visited = append(visited, typ)
91 switch t := typ.(type) {
92 case nil:
93 buf.WriteString("<nil>")
95 case *Basic:
96 if t.kind == UnsafePointer {
97 buf.WriteString("unsafe.")
99 if gcCompatibilityMode {
100 // forget the alias names
101 switch t.kind {
102 case Byte:
103 t = Typ[Uint8]
104 case Rune:
105 t = Typ[Int32]
108 buf.WriteString(t.name)
110 case *Array:
111 fmt.Fprintf(buf, "[%d]", t.len)
112 writeType(buf, t.elem, qf, visited)
114 case *Slice:
115 buf.WriteString("[]")
116 writeType(buf, t.elem, qf, visited)
118 case *Struct:
119 buf.WriteString("struct{")
120 for i, f := range t.fields {
121 if i > 0 {
122 buf.WriteString("; ")
124 if !f.embedded {
125 buf.WriteString(f.name)
126 buf.WriteByte(' ')
128 writeType(buf, f.typ, qf, visited)
129 if tag := t.Tag(i); tag != "" {
130 fmt.Fprintf(buf, " %q", tag)
133 buf.WriteByte('}')
135 case *Pointer:
136 buf.WriteByte('*')
137 writeType(buf, t.base, qf, visited)
139 case *Tuple:
140 writeTuple(buf, t, false, qf, visited)
142 case *Signature:
143 buf.WriteString("func")
144 writeSignature(buf, t, qf, visited)
146 case *Interface:
147 // We write the source-level methods and embedded types rather
148 // than the actual method set since resolved method signatures
149 // may have non-printable cycles if parameters have embedded
150 // interface types that (directly or indirectly) embed the
151 // current interface. For instance, consider the result type
152 // of m:
154 // type T interface{
155 // m() interface{ T }
156 // }
158 buf.WriteString("interface{")
159 empty := true
160 if gcCompatibilityMode {
161 // print flattened interface
162 // (useful to compare against gc-generated interfaces)
163 for i, m := range t.allMethods {
164 if i > 0 {
165 buf.WriteString("; ")
167 buf.WriteString(m.name)
168 writeSignature(buf, m.typ.(*Signature), qf, visited)
169 empty = false
171 } else {
172 // print explicit interface methods and embedded types
173 for i, m := range t.methods {
174 if i > 0 {
175 buf.WriteString("; ")
177 buf.WriteString(m.name)
178 writeSignature(buf, m.typ.(*Signature), qf, visited)
179 empty = false
181 for i, typ := range t.embeddeds {
182 if i > 0 || len(t.methods) > 0 {
183 buf.WriteString("; ")
185 writeType(buf, typ, qf, visited)
186 empty = false
189 if t.allMethods == nil || len(t.methods) > len(t.allMethods) {
190 if !empty {
191 buf.WriteByte(' ')
193 buf.WriteString("/* incomplete */")
195 buf.WriteByte('}')
197 case *Map:
198 buf.WriteString("map[")
199 writeType(buf, t.key, qf, visited)
200 buf.WriteByte(']')
201 writeType(buf, t.elem, qf, visited)
203 case *Chan:
204 var s string
205 var parens bool
206 switch t.dir {
207 case SendRecv:
208 s = "chan "
209 // chan (<-chan T) requires parentheses
210 if c, _ := t.elem.(*Chan); c != nil && c.dir == RecvOnly {
211 parens = true
213 case SendOnly:
214 s = "chan<- "
215 case RecvOnly:
216 s = "<-chan "
217 default:
218 panic("unreachable")
220 buf.WriteString(s)
221 if parens {
222 buf.WriteByte('(')
224 writeType(buf, t.elem, qf, visited)
225 if parens {
226 buf.WriteByte(')')
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)
235 // TODO(gri): function-local named types should be displayed
236 // differently from named types at package level to avoid
237 // ambiguity.
238 s = obj.name
240 buf.WriteString(s)
242 default:
243 // For externally defined implementations of Type.
244 buf.WriteString(t.String())
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(", ")
255 if v.name != "" {
256 buf.WriteString(v.name)
257 buf.WriteByte(' ')
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 // special case:
266 // append(s, "foo"...) leads to signature func([]byte, string...)
267 if t, ok := typ.Underlying().(*Basic); !ok || t.kind != String {
268 panic("internal error: string type expected")
270 writeType(buf, typ, qf, visited)
271 buf.WriteString("...")
272 continue
275 writeType(buf, typ, qf, visited)
278 buf.WriteByte(')')
281 // WriteSignature writes the representation of the signature sig to buf,
282 // without a leading "func" keyword.
283 // The Qualifier controls the printing of
284 // package-level objects, and may be nil.
285 func WriteSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier) {
286 writeSignature(buf, sig, qf, make([]Type, 0, 8))
289 func writeSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier, visited []Type) {
290 writeTuple(buf, sig.params, sig.variadic, qf, visited)
292 n := sig.results.Len()
293 if n == 0 {
294 // no result
295 return
298 buf.WriteByte(' ')
299 if n == 1 && sig.results.vars[0].name == "" {
300 // single unnamed result
301 writeType(buf, sig.results.vars[0].typ, qf, visited)
302 return
305 // multiple or named result(s)
306 writeTuple(buf, sig.results, false, qf, visited)