github.com/cockroachdb/tools@v0.0.0-20230222021103-a6d27438930d/cmd/godex/writetype.go (about) 1 // Copyright 2014 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. 4 5 // This file implements writing of types. The functionality is lifted 6 // directly from go/types, but now contains various modifications for 7 // nicer output. 8 // 9 // TODO(gri) back-port once we have a fixed interface and once the 10 // go/types API is not frozen anymore for the 1.3 release; and remove 11 // this implementation if possible. 12 13 package main 14 15 import "go/types" 16 17 func (p *printer) writeType(this *types.Package, typ types.Type) { 18 p.writeTypeInternal(this, typ, make([]types.Type, 8)) 19 } 20 21 // From go/types - leave for now to ease back-porting this code. 22 const GcCompatibilityMode = false 23 24 func (p *printer) writeTypeInternal(this *types.Package, typ types.Type, visited []types.Type) { 25 // Theoretically, this is a quadratic lookup algorithm, but in 26 // practice deeply nested composite types with unnamed component 27 // types are uncommon. This code is likely more efficient than 28 // using a map. 29 for _, t := range visited { 30 if t == typ { 31 p.printf("○%T", typ) // cycle to typ 32 return 33 } 34 } 35 visited = append(visited, typ) 36 37 switch t := typ.(type) { 38 case nil: 39 p.print("<nil>") 40 41 case *types.Basic: 42 if t.Kind() == types.UnsafePointer { 43 p.print("unsafe.") 44 } 45 if GcCompatibilityMode { 46 // forget the alias names 47 switch t.Kind() { 48 case types.Byte: 49 t = types.Typ[types.Uint8] 50 case types.Rune: 51 t = types.Typ[types.Int32] 52 } 53 } 54 p.print(t.Name()) 55 56 case *types.Array: 57 p.printf("[%d]", t.Len()) 58 p.writeTypeInternal(this, t.Elem(), visited) 59 60 case *types.Slice: 61 p.print("[]") 62 p.writeTypeInternal(this, t.Elem(), visited) 63 64 case *types.Struct: 65 n := t.NumFields() 66 if n == 0 { 67 p.print("struct{}") 68 return 69 } 70 71 p.print("struct {\n") 72 p.indent++ 73 for i := 0; i < n; i++ { 74 f := t.Field(i) 75 if !f.Anonymous() { 76 p.printf("%s ", f.Name()) 77 } 78 p.writeTypeInternal(this, f.Type(), visited) 79 if tag := t.Tag(i); tag != "" { 80 p.printf(" %q", tag) 81 } 82 p.print("\n") 83 } 84 p.indent-- 85 p.print("}") 86 87 case *types.Pointer: 88 p.print("*") 89 p.writeTypeInternal(this, t.Elem(), visited) 90 91 case *types.Tuple: 92 p.writeTuple(this, t, false, visited) 93 94 case *types.Signature: 95 p.print("func") 96 p.writeSignatureInternal(this, t, visited) 97 98 case *types.Interface: 99 // We write the source-level methods and embedded types rather 100 // than the actual method set since resolved method signatures 101 // may have non-printable cycles if parameters have anonymous 102 // interface types that (directly or indirectly) embed the 103 // current interface. For instance, consider the result type 104 // of m: 105 // 106 // type T interface{ 107 // m() interface{ T } 108 // } 109 // 110 n := t.NumMethods() 111 if n == 0 { 112 p.print("interface{}") 113 return 114 } 115 116 p.print("interface {\n") 117 p.indent++ 118 if GcCompatibilityMode { 119 // print flattened interface 120 // (useful to compare against gc-generated interfaces) 121 for i := 0; i < n; i++ { 122 m := t.Method(i) 123 p.print(m.Name()) 124 p.writeSignatureInternal(this, m.Type().(*types.Signature), visited) 125 p.print("\n") 126 } 127 } else { 128 // print explicit interface methods and embedded types 129 for i, n := 0, t.NumExplicitMethods(); i < n; i++ { 130 m := t.ExplicitMethod(i) 131 p.print(m.Name()) 132 p.writeSignatureInternal(this, m.Type().(*types.Signature), visited) 133 p.print("\n") 134 } 135 for i, n := 0, t.NumEmbeddeds(); i < n; i++ { 136 typ := t.EmbeddedType(i) 137 p.writeTypeInternal(this, typ, visited) 138 p.print("\n") 139 } 140 } 141 p.indent-- 142 p.print("}") 143 144 case *types.Map: 145 p.print("map[") 146 p.writeTypeInternal(this, t.Key(), visited) 147 p.print("]") 148 p.writeTypeInternal(this, t.Elem(), visited) 149 150 case *types.Chan: 151 var s string 152 var parens bool 153 switch t.Dir() { 154 case types.SendRecv: 155 s = "chan " 156 // chan (<-chan T) requires parentheses 157 if c, _ := t.Elem().(*types.Chan); c != nil && c.Dir() == types.RecvOnly { 158 parens = true 159 } 160 case types.SendOnly: 161 s = "chan<- " 162 case types.RecvOnly: 163 s = "<-chan " 164 default: 165 panic("unreachable") 166 } 167 p.print(s) 168 if parens { 169 p.print("(") 170 } 171 p.writeTypeInternal(this, t.Elem(), visited) 172 if parens { 173 p.print(")") 174 } 175 176 case *types.Named: 177 s := "<Named w/o object>" 178 if obj := t.Obj(); obj != nil { 179 if pkg := obj.Pkg(); pkg != nil { 180 if pkg != this { 181 p.print(pkg.Path()) 182 p.print(".") 183 } 184 // TODO(gri): function-local named types should be displayed 185 // differently from named types at package level to avoid 186 // ambiguity. 187 } 188 s = obj.Name() 189 } 190 p.print(s) 191 192 default: 193 // For externally defined implementations of Type. 194 p.print(t.String()) 195 } 196 } 197 198 func (p *printer) writeTuple(this *types.Package, tup *types.Tuple, variadic bool, visited []types.Type) { 199 p.print("(") 200 for i, n := 0, tup.Len(); i < n; i++ { 201 if i > 0 { 202 p.print(", ") 203 } 204 v := tup.At(i) 205 if name := v.Name(); name != "" { 206 p.print(name) 207 p.print(" ") 208 } 209 typ := v.Type() 210 if variadic && i == n-1 { 211 p.print("...") 212 typ = typ.(*types.Slice).Elem() 213 } 214 p.writeTypeInternal(this, typ, visited) 215 } 216 p.print(")") 217 } 218 219 func (p *printer) writeSignature(this *types.Package, sig *types.Signature) { 220 p.writeSignatureInternal(this, sig, make([]types.Type, 8)) 221 } 222 223 func (p *printer) writeSignatureInternal(this *types.Package, sig *types.Signature, visited []types.Type) { 224 p.writeTuple(this, sig.Params(), sig.Variadic(), visited) 225 226 res := sig.Results() 227 n := res.Len() 228 if n == 0 { 229 // no result 230 return 231 } 232 233 p.print(" ") 234 if n == 1 && res.At(0).Name() == "" { 235 // single unnamed result 236 p.writeTypeInternal(this, res.At(0).Type(), visited) 237 return 238 } 239 240 // multiple or named result(s) 241 p.writeTuple(this, res, false, visited) 242 }