+++ /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)
-}