mirror of
https://github.com/golang/go
synced 2024-11-26 17:56:55 -07:00
cmd/compile/internal/types2: use a typeWriter to write types (cleanup)
Rather then passing through a buffer, qualified, and visited list to each helper function, maintain state in a typeWriter object and use methods on it. This cleans up this code quite a bit. Use a map ("seen") for cycle detection rather than a list. Move printing of [ and ] for type lists into the typeList method so that callers don't have to do it themselves. Change-Id: I1346373e979cb90710fbc073953aa51e2f6581f9 Reviewed-on: https://go-review.googlesource.com/c/go/+/345890 Trust: Robert Griesemer <gri@golang.org> Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
parent
61120c634c
commit
5f0d821add
@ -476,7 +476,7 @@ func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if named, _ := typ.(*Named); named != nil && named.TParams().Len() > 0 {
|
if named, _ := typ.(*Named); named != nil && named.TParams().Len() > 0 {
|
||||||
writeTParamList(buf, named.TParams().list(), qf, nil)
|
newTypeWriter(buf, qf).tParamList(named.TParams().list())
|
||||||
}
|
}
|
||||||
if tname.IsAlias() {
|
if tname.IsAlias() {
|
||||||
buf.WriteString(" =")
|
buf.WriteString(" =")
|
||||||
|
@ -259,10 +259,9 @@ func instantiatedHash(typ *Named, targs []Type) string {
|
|||||||
assert(instanceHashing == 0)
|
assert(instanceHashing == 0)
|
||||||
instanceHashing++
|
instanceHashing++
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
writeTypeName(&buf, typ.obj, nil)
|
w := newTypeWriter(&buf, nil)
|
||||||
buf.WriteByte('[')
|
w.typeName(typ.obj)
|
||||||
writeTypeList(&buf, targs, nil, nil)
|
w.typeList(targs)
|
||||||
buf.WriteByte(']')
|
|
||||||
instanceHashing--
|
instanceHashing--
|
||||||
|
|
||||||
// With respect to the represented type, whether a
|
// With respect to the represented type, whether a
|
||||||
|
@ -59,9 +59,7 @@ func (l *TypeList) String() string {
|
|||||||
return "[]"
|
return "[]"
|
||||||
}
|
}
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
buf.WriteByte('[')
|
newTypeWriter(&buf, nil).typeList(l.types)
|
||||||
writeTypeList(&buf, l.types, nil, nil)
|
|
||||||
buf.WriteByte(']')
|
|
||||||
return buf.String()
|
return buf.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,79 +52,87 @@ func TypeString(typ Type, qf Qualifier) string {
|
|||||||
// The Qualifier controls the printing of
|
// The Qualifier controls the printing of
|
||||||
// package-level objects, and may be nil.
|
// package-level objects, and may be nil.
|
||||||
func WriteType(buf *bytes.Buffer, typ Type, qf Qualifier) {
|
func WriteType(buf *bytes.Buffer, typ Type, qf Qualifier) {
|
||||||
writeType(buf, typ, qf, make([]Type, 0, 8))
|
newTypeWriter(buf, qf).typ(typ)
|
||||||
}
|
}
|
||||||
|
|
||||||
// instanceMarker is the prefix for an instantiated type
|
// instanceMarker is the prefix for an instantiated type in unexpanded form.
|
||||||
// in "non-evaluated" instance form.
|
|
||||||
const instanceMarker = '#'
|
const instanceMarker = '#'
|
||||||
|
|
||||||
func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) {
|
type typeWriter struct {
|
||||||
// Theoretically, this is a quadratic lookup algorithm, but in
|
buf *bytes.Buffer
|
||||||
// practice deeply nested composite types with unnamed component
|
seen map[Type]bool
|
||||||
// types are uncommon. This code is likely more efficient than
|
qf Qualifier
|
||||||
// using a map.
|
}
|
||||||
for _, t := range visited {
|
|
||||||
if t == typ {
|
func newTypeWriter(buf *bytes.Buffer, qf Qualifier) *typeWriter {
|
||||||
fmt.Fprintf(buf, "○%T", goTypeName(typ)) // cycle to typ
|
return &typeWriter{buf, make(map[Type]bool), qf}
|
||||||
return
|
}
|
||||||
}
|
|
||||||
|
func (w *typeWriter) byte(b byte) { w.buf.WriteByte(b) }
|
||||||
|
func (w *typeWriter) string(s string) { w.buf.WriteString(s) }
|
||||||
|
func (w *typeWriter) writef(format string, args ...interface{}) { fmt.Fprintf(w.buf, format, args...) }
|
||||||
|
|
||||||
|
func (w *typeWriter) typ(typ Type) {
|
||||||
|
if w.seen[typ] {
|
||||||
|
w.writef("○%T", goTypeName(typ)) // cycle to typ
|
||||||
|
return
|
||||||
}
|
}
|
||||||
visited = append(visited, typ)
|
w.seen[typ] = true
|
||||||
|
defer delete(w.seen, typ)
|
||||||
|
|
||||||
switch t := typ.(type) {
|
switch t := typ.(type) {
|
||||||
case nil:
|
case nil:
|
||||||
buf.WriteString("<nil>")
|
w.string("<nil>")
|
||||||
|
|
||||||
case *Basic:
|
case *Basic:
|
||||||
// exported basic types go into package unsafe
|
// exported basic types go into package unsafe
|
||||||
// (currently this is just unsafe.Pointer)
|
// (currently this is just unsafe.Pointer)
|
||||||
if isExported(t.name) {
|
if isExported(t.name) {
|
||||||
if obj, _ := Unsafe.scope.Lookup(t.name).(*TypeName); obj != nil {
|
if obj, _ := Unsafe.scope.Lookup(t.name).(*TypeName); obj != nil {
|
||||||
writeTypeName(buf, obj, qf)
|
w.typeName(obj)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
buf.WriteString(t.name)
|
w.string(t.name)
|
||||||
|
|
||||||
case *Array:
|
case *Array:
|
||||||
fmt.Fprintf(buf, "[%d]", t.len)
|
w.writef("[%d]", t.len)
|
||||||
writeType(buf, t.elem, qf, visited)
|
w.typ(t.elem)
|
||||||
|
|
||||||
case *Slice:
|
case *Slice:
|
||||||
buf.WriteString("[]")
|
w.string("[]")
|
||||||
writeType(buf, t.elem, qf, visited)
|
w.typ(t.elem)
|
||||||
|
|
||||||
case *Struct:
|
case *Struct:
|
||||||
buf.WriteString("struct{")
|
w.string("struct{")
|
||||||
for i, f := range t.fields {
|
for i, f := range t.fields {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
buf.WriteString("; ")
|
w.string("; ")
|
||||||
}
|
}
|
||||||
// This doesn't do the right thing for embedded type
|
// This doesn't do the right thing for embedded type
|
||||||
// aliases where we should print the alias name, not
|
// aliases where we should print the alias name, not
|
||||||
// the aliased type (see issue #44410).
|
// the aliased type (see issue #44410).
|
||||||
if !f.embedded {
|
if !f.embedded {
|
||||||
buf.WriteString(f.name)
|
w.string(f.name)
|
||||||
buf.WriteByte(' ')
|
w.byte(' ')
|
||||||
}
|
}
|
||||||
writeType(buf, f.typ, qf, visited)
|
w.typ(f.typ)
|
||||||
if tag := t.Tag(i); tag != "" {
|
if tag := t.Tag(i); tag != "" {
|
||||||
fmt.Fprintf(buf, " %q", tag)
|
w.writef(" %q", tag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
buf.WriteByte('}')
|
w.byte('}')
|
||||||
|
|
||||||
case *Pointer:
|
case *Pointer:
|
||||||
buf.WriteByte('*')
|
w.byte('*')
|
||||||
writeType(buf, t.base, qf, visited)
|
w.typ(t.base)
|
||||||
|
|
||||||
case *Tuple:
|
case *Tuple:
|
||||||
writeTuple(buf, t, false, qf, visited)
|
w.tuple(t, false)
|
||||||
|
|
||||||
case *Signature:
|
case *Signature:
|
||||||
buf.WriteString("func")
|
w.string("func")
|
||||||
writeSignature(buf, t, qf, visited)
|
w.signature(t)
|
||||||
|
|
||||||
case *Union:
|
case *Union:
|
||||||
// Unions only appear as (syntactic) embedded elements
|
// Unions only appear as (syntactic) embedded elements
|
||||||
@ -134,39 +142,39 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) {
|
|||||||
}
|
}
|
||||||
for i, t := range t.terms {
|
for i, t := range t.terms {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
buf.WriteByte('|')
|
w.byte('|')
|
||||||
}
|
}
|
||||||
if t.tilde {
|
if t.tilde {
|
||||||
buf.WriteByte('~')
|
w.byte('~')
|
||||||
}
|
}
|
||||||
writeType(buf, t.typ, qf, visited)
|
w.typ(t.typ)
|
||||||
}
|
}
|
||||||
|
|
||||||
case *Interface:
|
case *Interface:
|
||||||
buf.WriteString("interface{")
|
w.string("interface{")
|
||||||
first := true
|
first := true
|
||||||
for _, m := range t.methods {
|
for _, m := range t.methods {
|
||||||
if !first {
|
if !first {
|
||||||
buf.WriteString("; ")
|
w.string("; ")
|
||||||
}
|
}
|
||||||
first = false
|
first = false
|
||||||
buf.WriteString(m.name)
|
w.string(m.name)
|
||||||
writeSignature(buf, m.typ.(*Signature), qf, visited)
|
w.signature(m.typ.(*Signature))
|
||||||
}
|
}
|
||||||
for _, typ := range t.embeddeds {
|
for _, typ := range t.embeddeds {
|
||||||
if !first {
|
if !first {
|
||||||
buf.WriteString("; ")
|
w.string("; ")
|
||||||
}
|
}
|
||||||
first = false
|
first = false
|
||||||
writeType(buf, typ, qf, visited)
|
w.typ(typ)
|
||||||
}
|
}
|
||||||
buf.WriteByte('}')
|
w.byte('}')
|
||||||
|
|
||||||
case *Map:
|
case *Map:
|
||||||
buf.WriteString("map[")
|
w.string("map[")
|
||||||
writeType(buf, t.key, qf, visited)
|
w.typ(t.key)
|
||||||
buf.WriteByte(']')
|
w.byte(']')
|
||||||
writeType(buf, t.elem, qf, visited)
|
w.typ(t.elem)
|
||||||
|
|
||||||
case *Chan:
|
case *Chan:
|
||||||
var s string
|
var s string
|
||||||
@ -185,28 +193,26 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) {
|
|||||||
default:
|
default:
|
||||||
unreachable()
|
unreachable()
|
||||||
}
|
}
|
||||||
buf.WriteString(s)
|
w.string(s)
|
||||||
if parens {
|
if parens {
|
||||||
buf.WriteByte('(')
|
w.byte('(')
|
||||||
}
|
}
|
||||||
writeType(buf, t.elem, qf, visited)
|
w.typ(t.elem)
|
||||||
if parens {
|
if parens {
|
||||||
buf.WriteByte(')')
|
w.byte(')')
|
||||||
}
|
}
|
||||||
|
|
||||||
case *Named:
|
case *Named:
|
||||||
if t.instPos != nil {
|
if t.instPos != nil {
|
||||||
buf.WriteByte(instanceMarker)
|
w.byte(instanceMarker)
|
||||||
}
|
}
|
||||||
writeTypeName(buf, t.obj, qf)
|
w.typeName(t.obj)
|
||||||
if t.targs != nil {
|
if t.targs != nil {
|
||||||
// instantiated type
|
// instantiated type
|
||||||
buf.WriteByte('[')
|
w.typeList(t.targs.list())
|
||||||
writeTypeList(buf, t.targs.list(), qf, visited)
|
|
||||||
buf.WriteByte(']')
|
|
||||||
} else if t.TParams().Len() != 0 {
|
} else if t.TParams().Len() != 0 {
|
||||||
// parameterized type
|
// parameterized type
|
||||||
writeTParamList(buf, t.TParams().list(), qf, visited)
|
w.tParamList(t.TParams().list())
|
||||||
}
|
}
|
||||||
|
|
||||||
case *TypeParam:
|
case *TypeParam:
|
||||||
@ -217,33 +223,35 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) {
|
|||||||
// we maybe need a separate function that won't be changed
|
// we maybe need a separate function that won't be changed
|
||||||
// for debugging purposes.
|
// for debugging purposes.
|
||||||
if t.obj.pkg != nil {
|
if t.obj.pkg != nil {
|
||||||
writePackage(buf, t.obj.pkg, qf)
|
writePackage(w.buf, t.obj.pkg, w.qf)
|
||||||
}
|
}
|
||||||
s = t.obj.name
|
s = t.obj.name
|
||||||
}
|
}
|
||||||
buf.WriteString(s + subscript(t.id))
|
w.string(s + subscript(t.id))
|
||||||
|
|
||||||
case *top:
|
case *top:
|
||||||
buf.WriteString("⊤")
|
w.string("⊤")
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// For externally defined implementations of Type.
|
// For externally defined implementations of Type.
|
||||||
// Note: In this case cycles won't be caught.
|
// Note: In this case cycles won't be caught.
|
||||||
buf.WriteString(t.String())
|
w.string(t.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeTypeList(buf *bytes.Buffer, list []Type, qf Qualifier, visited []Type) {
|
func (w *typeWriter) typeList(list []Type) {
|
||||||
|
w.byte('[')
|
||||||
for i, typ := range list {
|
for i, typ := range list {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
buf.WriteString(", ")
|
w.string(", ")
|
||||||
}
|
}
|
||||||
writeType(buf, typ, qf, visited)
|
w.typ(typ)
|
||||||
}
|
}
|
||||||
|
w.byte(']')
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeTParamList(buf *bytes.Buffer, list []*TypeParam, qf Qualifier, visited []Type) {
|
func (w *typeWriter) tParamList(list []*TypeParam) {
|
||||||
buf.WriteString("[")
|
w.byte('[')
|
||||||
var prev Type
|
var prev Type
|
||||||
for i, tpar := range list {
|
for i, tpar := range list {
|
||||||
// Determine the type parameter and its constraint.
|
// Determine the type parameter and its constraint.
|
||||||
@ -257,36 +265,36 @@ func writeTParamList(buf *bytes.Buffer, list []*TypeParam, qf Qualifier, visited
|
|||||||
if i > 0 {
|
if i > 0 {
|
||||||
if bound != prev {
|
if bound != prev {
|
||||||
// bound changed - write previous one before advancing
|
// bound changed - write previous one before advancing
|
||||||
buf.WriteByte(' ')
|
w.byte(' ')
|
||||||
writeType(buf, prev, qf, visited)
|
w.typ(prev)
|
||||||
}
|
}
|
||||||
buf.WriteString(", ")
|
w.string(", ")
|
||||||
}
|
}
|
||||||
prev = bound
|
prev = bound
|
||||||
|
|
||||||
if tpar != nil {
|
if tpar != nil {
|
||||||
writeType(buf, tpar, qf, visited)
|
w.typ(tpar)
|
||||||
} else {
|
} else {
|
||||||
buf.WriteString(tpar.obj.name)
|
w.string(tpar.obj.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if prev != nil {
|
if prev != nil {
|
||||||
buf.WriteByte(' ')
|
w.byte(' ')
|
||||||
writeType(buf, prev, qf, visited)
|
w.typ(prev)
|
||||||
}
|
}
|
||||||
buf.WriteByte(']')
|
w.byte(']')
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeTypeName(buf *bytes.Buffer, obj *TypeName, qf Qualifier) {
|
func (w *typeWriter) typeName(obj *TypeName) {
|
||||||
if obj == nil {
|
if obj == nil {
|
||||||
assert(instanceHashing == 0) // we need an object for instance hashing
|
assert(instanceHashing == 0) // we need an object for instance hashing
|
||||||
buf.WriteString("<Named w/o object>")
|
w.string("<Named w/o object>")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if obj.pkg != nil {
|
if obj.pkg != nil {
|
||||||
writePackage(buf, obj.pkg, qf)
|
writePackage(w.buf, obj.pkg, w.qf)
|
||||||
}
|
}
|
||||||
buf.WriteString(obj.name)
|
w.string(obj.name)
|
||||||
|
|
||||||
if instanceHashing != 0 {
|
if instanceHashing != 0 {
|
||||||
// For local defined types, use the (original!) TypeName's scope
|
// For local defined types, use the (original!) TypeName's scope
|
||||||
@ -298,7 +306,7 @@ func writeTypeName(buf *bytes.Buffer, obj *TypeName, qf Qualifier) {
|
|||||||
for typ.orig != typ {
|
for typ.orig != typ {
|
||||||
typ = typ.orig
|
typ = typ.orig
|
||||||
}
|
}
|
||||||
writeScopeNumbers(buf, typ.obj.parent)
|
w.writeScopeNumbers(typ.obj.parent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -306,28 +314,28 @@ func writeTypeName(buf *bytes.Buffer, obj *TypeName, qf Qualifier) {
|
|||||||
// in the form ".i.j.k" where i, j, k, etc. stand for scope numbers.
|
// in the form ".i.j.k" where i, j, k, etc. stand for scope numbers.
|
||||||
// If a scope is nil or has no parent (such as a package scope), nothing
|
// If a scope is nil or has no parent (such as a package scope), nothing
|
||||||
// is written.
|
// is written.
|
||||||
func writeScopeNumbers(buf *bytes.Buffer, s *Scope) {
|
func (w *typeWriter) writeScopeNumbers(s *Scope) {
|
||||||
if s != nil && s.number > 0 {
|
if s != nil && s.number > 0 {
|
||||||
writeScopeNumbers(buf, s.parent)
|
w.writeScopeNumbers(s.parent)
|
||||||
fmt.Fprintf(buf, ".%d", s.number)
|
w.writef(".%d", s.number)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeTuple(buf *bytes.Buffer, tup *Tuple, variadic bool, qf Qualifier, visited []Type) {
|
func (w *typeWriter) tuple(tup *Tuple, variadic bool) {
|
||||||
buf.WriteByte('(')
|
w.byte('(')
|
||||||
if tup != nil {
|
if tup != nil {
|
||||||
for i, v := range tup.vars {
|
for i, v := range tup.vars {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
buf.WriteString(", ")
|
w.string(", ")
|
||||||
}
|
}
|
||||||
if v.name != "" {
|
if v.name != "" {
|
||||||
buf.WriteString(v.name)
|
w.string(v.name)
|
||||||
buf.WriteByte(' ')
|
w.byte(' ')
|
||||||
}
|
}
|
||||||
typ := v.typ
|
typ := v.typ
|
||||||
if variadic && i == len(tup.vars)-1 {
|
if variadic && i == len(tup.vars)-1 {
|
||||||
if s, ok := typ.(*Slice); ok {
|
if s, ok := typ.(*Slice); ok {
|
||||||
buf.WriteString("...")
|
w.string("...")
|
||||||
typ = s.elem
|
typ = s.elem
|
||||||
} else {
|
} else {
|
||||||
// special case:
|
// special case:
|
||||||
@ -335,15 +343,15 @@ func writeTuple(buf *bytes.Buffer, tup *Tuple, variadic bool, qf Qualifier, visi
|
|||||||
if t := asBasic(typ); t == nil || t.kind != String {
|
if t := asBasic(typ); t == nil || t.kind != String {
|
||||||
panic("expected string type")
|
panic("expected string type")
|
||||||
}
|
}
|
||||||
writeType(buf, typ, qf, visited)
|
w.typ(typ)
|
||||||
buf.WriteString("...")
|
w.string("...")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
writeType(buf, typ, qf, visited)
|
w.typ(typ)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
buf.WriteByte(')')
|
w.byte(')')
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteSignature writes the representation of the signature sig to buf,
|
// WriteSignature writes the representation of the signature sig to buf,
|
||||||
@ -351,15 +359,15 @@ func writeTuple(buf *bytes.Buffer, tup *Tuple, variadic bool, qf Qualifier, visi
|
|||||||
// The Qualifier controls the printing of
|
// The Qualifier controls the printing of
|
||||||
// package-level objects, and may be nil.
|
// package-level objects, and may be nil.
|
||||||
func WriteSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier) {
|
func WriteSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier) {
|
||||||
writeSignature(buf, sig, qf, make([]Type, 0, 8))
|
newTypeWriter(buf, qf).signature(sig)
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier, visited []Type) {
|
func (w *typeWriter) signature(sig *Signature) {
|
||||||
if sig.TParams().Len() != 0 {
|
if sig.TParams().Len() != 0 {
|
||||||
writeTParamList(buf, sig.TParams().list(), qf, visited)
|
w.tParamList(sig.TParams().list())
|
||||||
}
|
}
|
||||||
|
|
||||||
writeTuple(buf, sig.params, sig.variadic, qf, visited)
|
w.tuple(sig.params, sig.variadic)
|
||||||
|
|
||||||
n := sig.results.Len()
|
n := sig.results.Len()
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
@ -367,15 +375,15 @@ func writeSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier, visited []T
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
buf.WriteByte(' ')
|
w.byte(' ')
|
||||||
if n == 1 && sig.results.vars[0].name == "" {
|
if n == 1 && sig.results.vars[0].name == "" {
|
||||||
// single unnamed result
|
// single unnamed result
|
||||||
writeType(buf, sig.results.vars[0].typ, qf, visited)
|
w.typ(sig.results.vars[0].typ)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// multiple or named result(s)
|
// multiple or named result(s)
|
||||||
writeTuple(buf, sig.results, false, qf, visited)
|
w.tuple(sig.results, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// subscript returns the decimal (utf8) representation of x using subscript digits.
|
// subscript returns the decimal (utf8) representation of x using subscript digits.
|
||||||
|
@ -76,16 +76,17 @@ type tparamsList struct {
|
|||||||
// String returns a string representation for a tparamsList. For debugging.
|
// String returns a string representation for a tparamsList. For debugging.
|
||||||
func (d *tparamsList) String() string {
|
func (d *tparamsList) String() string {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
buf.WriteByte('[')
|
w := newTypeWriter(&buf, nil)
|
||||||
|
w.byte('[')
|
||||||
for i, tpar := range d.tparams {
|
for i, tpar := range d.tparams {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
buf.WriteString(", ")
|
w.string(", ")
|
||||||
}
|
}
|
||||||
writeType(&buf, tpar, nil, nil)
|
w.typ(tpar)
|
||||||
buf.WriteString(": ")
|
w.string(": ")
|
||||||
writeType(&buf, d.at(i), nil, nil)
|
w.typ(d.at(i))
|
||||||
}
|
}
|
||||||
buf.WriteByte(']')
|
w.byte(']')
|
||||||
return buf.String()
|
return buf.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user