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.
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
{
33 return func(other
*Package
) string {
35 return "" // same package; unqualified
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
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 {
67 WriteType(&buf
, typ
, qf
)
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
83 for _
, t
:= range visited
{
85 fmt
.Fprintf(buf
, "○%T", typ
) // cycle to typ
89 visited
= append(visited
, typ
)
91 switch t
:= typ
.(type) {
93 buf
.WriteString("<nil>")
96 if t
.kind
== UnsafePointer
{
97 buf
.WriteString("unsafe.")
99 if gcCompatibilityMode
{
100 // forget the alias names
108 buf
.WriteString(t
.name
)
111 fmt
.Fprintf(buf
, "[%d]", t
.len)
112 writeType(buf
, t
.elem
, qf
, visited
)
115 buf
.WriteString("[]")
116 writeType(buf
, t
.elem
, qf
, visited
)
119 buf
.WriteString("struct{")
120 for i
, f
:= range t
.fields
{
122 buf
.WriteString("; ")
125 buf
.WriteString(f
.name
)
128 writeType(buf
, f
.typ
, qf
, visited
)
129 if tag
:= t
.Tag(i
); tag
!= "" {
130 fmt
.Fprintf(buf
, " %q", tag
)
137 writeType(buf
, t
.base
, qf
, visited
)
140 writeTuple(buf
, t
, false, qf
, visited
)
143 buf
.WriteString("func")
144 writeSignature(buf
, t
, qf
, visited
)
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
155 // m() interface{ T }
158 buf
.WriteString("interface{")
160 if gcCompatibilityMode
{
161 // print flattened interface
162 // (useful to compare against gc-generated interfaces)
163 for i
, m
:= range t
.allMethods
{
165 buf
.WriteString("; ")
167 buf
.WriteString(m
.name
)
168 writeSignature(buf
, m
.typ
.(*Signature
), qf
, visited
)
172 // print explicit interface methods and embedded types
173 for i
, m
:= range t
.methods
{
175 buf
.WriteString("; ")
177 buf
.WriteString(m
.name
)
178 writeSignature(buf
, m
.typ
.(*Signature
), qf
, visited
)
181 for i
, typ
:= range t
.embeddeds
{
182 if i
> 0 ||
len(t
.methods
) > 0 {
183 buf
.WriteString("; ")
185 writeType(buf
, typ
, qf
, visited
)
189 if t
.allMethods
== nil ||
len(t
.methods
) > len(t
.allMethods
) {
193 buf
.WriteString("/* incomplete */")
198 buf
.WriteString("map[")
199 writeType(buf
, t
.key
, qf
, visited
)
201 writeType(buf
, t
.elem
, qf
, visited
)
209 // chan (<-chan T) requires parentheses
210 if c
, _
:= t
.elem
.(*Chan
); c
!= nil && c
.dir
== RecvOnly
{
224 writeType(buf
, t
.elem
, qf
, visited
)
230 s
:= "<Named w/o object>"
231 if obj
:= t
.obj
; obj
!= 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
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
) {
251 for i
, v
:= range tup
.vars
{
253 buf
.WriteString(", ")
256 buf
.WriteString(v
.name
)
260 if variadic
&& i
== len(tup
.vars
)-1 {
261 if s
, ok
:= typ
.(*Slice
); ok
{
262 buf
.WriteString("...")
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("...")
275 writeType(buf
, typ
, qf
, visited
)
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()
299 if n
== 1 && sig
.results
.vars
[0].name
== "" {
300 // single unnamed result
301 writeType(buf
, sig
.results
.vars
[0].typ
, qf
, visited
)
305 // multiple or named result(s)
306 writeTuple(buf
, sig
.results
, false, qf
, visited
)