--- /dev/null
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements writing of types. The functionality is lifted
+// directly from go/types, but now contains various modifications for
+// nicer output.
+//
+// TODO(gri) back-port once we have a fixed interface and once the
+// go/types API is not frozen anymore for the 1.3 release; and remove
+// this implementation if possible.
+
+package main
+
+import "go/types"
+
+func (p *printer) writeType(this *types.Package, typ types.Type) {
+ p.writeTypeInternal(this, typ, make([]types.Type, 8))
+}
+
+// From go/types - leave for now to ease back-porting this code.
+const GcCompatibilityMode = false
+
+func (p *printer) writeTypeInternal(this *types.Package, typ types.Type, visited []types.Type) {
+ // Theoretically, this is a quadratic lookup algorithm, but in
+ // practice deeply nested composite types with unnamed component
+ // types are uncommon. This code is likely more efficient than
+ // using a map.
+ for _, t := range visited {
+ if t == typ {
+ p.printf("○%T", typ) // cycle to typ
+ return
+ }
+ }
+ visited = append(visited, typ)
+
+ switch t := typ.(type) {
+ case nil:
+ p.print("<nil>")
+
+ case *types.Basic:
+ if t.Kind() == types.UnsafePointer {
+ p.print("unsafe.")
+ }
+ if GcCompatibilityMode {
+ // forget the alias names
+ switch t.Kind() {
+ case types.Byte:
+ t = types.Typ[types.Uint8]
+ case types.Rune:
+ t = types.Typ[types.Int32]
+ }
+ }
+ p.print(t.Name())
+
+ case *types.Array:
+ p.printf("[%d]", t.Len())
+ p.writeTypeInternal(this, t.Elem(), visited)
+
+ case *types.Slice:
+ p.print("[]")
+ p.writeTypeInternal(this, t.Elem(), visited)
+
+ case *types.Struct:
+ n := t.NumFields()
+ if n == 0 {
+ p.print("struct{}")
+ return
+ }
+
+ p.print("struct {\n")
+ p.indent++
+ for i := 0; i < n; i++ {
+ f := t.Field(i)
+ if !f.Anonymous() {
+ p.printf("%s ", f.Name())
+ }
+ p.writeTypeInternal(this, f.Type(), visited)
+ if tag := t.Tag(i); tag != "" {
+ p.printf(" %q", tag)
+ }
+ p.print("\n")
+ }
+ p.indent--
+ p.print("}")
+
+ case *types.Pointer:
+ p.print("*")
+ p.writeTypeInternal(this, t.Elem(), visited)
+
+ case *types.Tuple:
+ p.writeTuple(this, t, false, visited)
+
+ case *types.Signature:
+ p.print("func")
+ p.writeSignatureInternal(this, t, visited)
+
+ case *types.Interface:
+ // We write the source-level methods and embedded types rather
+ // than the actual method set since resolved method signatures
+ // may have non-printable cycles if parameters have anonymous
+ // interface types that (directly or indirectly) embed the
+ // current interface. For instance, consider the result type
+ // of m:
+ //
+ // type T interface{
+ // m() interface{ T }
+ // }
+ //
+ n := t.NumMethods()
+ if n == 0 {
+ p.print("interface{}")
+ return
+ }
+
+ p.print("interface {\n")
+ p.indent++
+ if GcCompatibilityMode {
+ // print flattened interface
+ // (useful to compare against gc-generated interfaces)
+ for i := 0; i < n; i++ {
+ m := t.Method(i)
+ p.print(m.Name())
+ p.writeSignatureInternal(this, m.Type().(*types.Signature), visited)
+ p.print("\n")
+ }
+ } else {
+ // print explicit interface methods and embedded types
+ for i, n := 0, t.NumExplicitMethods(); i < n; i++ {
+ m := t.ExplicitMethod(i)
+ p.print(m.Name())
+ p.writeSignatureInternal(this, m.Type().(*types.Signature), visited)
+ p.print("\n")
+ }
+ for i, n := 0, t.NumEmbeddeds(); i < n; i++ {
+ typ := t.EmbeddedType(i)
+ p.writeTypeInternal(this, typ, visited)
+ p.print("\n")
+ }
+ }
+ p.indent--
+ p.print("}")
+
+ case *types.Map:
+ p.print("map[")
+ p.writeTypeInternal(this, t.Key(), visited)
+ p.print("]")
+ p.writeTypeInternal(this, t.Elem(), visited)
+
+ case *types.Chan:
+ var s string
+ var parens bool
+ switch t.Dir() {
+ case types.SendRecv:
+ s = "chan "
+ // chan (<-chan T) requires parentheses
+ if c, _ := t.Elem().(*types.Chan); c != nil && c.Dir() == types.RecvOnly {
+ parens = true
+ }
+ case types.SendOnly:
+ s = "chan<- "
+ case types.RecvOnly:
+ s = "<-chan "
+ default:
+ panic("unreachable")
+ }
+ p.print(s)
+ if parens {
+ p.print("(")
+ }
+ p.writeTypeInternal(this, t.Elem(), visited)
+ if parens {
+ p.print(")")
+ }
+
+ case *types.Named:
+ s := "<Named w/o object>"
+ if obj := t.Obj(); obj != nil {
+ if pkg := obj.Pkg(); pkg != nil {
+ if pkg != this {
+ p.print(pkg.Path())
+ p.print(".")
+ }
+ // TODO(gri): function-local named types should be displayed
+ // differently from named types at package level to avoid
+ // ambiguity.
+ }
+ s = obj.Name()
+ }
+ p.print(s)
+
+ default:
+ // For externally defined implementations of Type.
+ p.print(t.String())
+ }
+}
+
+func (p *printer) writeTuple(this *types.Package, tup *types.Tuple, variadic bool, visited []types.Type) {
+ p.print("(")
+ for i, n := 0, tup.Len(); i < n; i++ {
+ if i > 0 {
+ p.print(", ")
+ }
+ v := tup.At(i)
+ if name := v.Name(); name != "" {
+ p.print(name)
+ p.print(" ")
+ }
+ typ := v.Type()
+ if variadic && i == n-1 {
+ p.print("...")
+ typ = typ.(*types.Slice).Elem()
+ }
+ p.writeTypeInternal(this, typ, visited)
+ }
+ p.print(")")
+}
+
+func (p *printer) writeSignature(this *types.Package, sig *types.Signature) {
+ p.writeSignatureInternal(this, sig, make([]types.Type, 8))
+}
+
+func (p *printer) writeSignatureInternal(this *types.Package, sig *types.Signature, visited []types.Type) {
+ p.writeTuple(this, sig.Params(), sig.Variadic(), visited)
+
+ res := sig.Results()
+ n := res.Len()
+ if n == 0 {
+ // no result
+ return
+ }
+
+ p.print(" ")
+ if n == 1 && res.At(0).Name() == "" {
+ // single unnamed result
+ p.writeTypeInternal(this, res.At(0).Type(), visited)
+ return
+ }
+
+ // multiple or named result(s)
+ p.writeTuple(this, res, false, visited)
+}