]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile/internal/types2: use a typeWriter to write types (cleanup)
authorRobert Griesemer <gri@golang.org>
Sat, 28 Aug 2021 20:00:41 +0000 (13:00 -0700)
committerRobert Griesemer <gri@golang.org>
Mon, 30 Aug 2021 20:22:38 +0000 (20:22 +0000)
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>
src/cmd/compile/internal/types2/object.go
src/cmd/compile/internal/types2/subst.go
src/cmd/compile/internal/types2/typelists.go
src/cmd/compile/internal/types2/typestring.go
src/cmd/compile/internal/types2/unify.go

index c1466f24edf16a3235a46f6ad1897fb802e7e87b..a3f5f913aa56b88ca5a97bb80c7b01263b33add1 100644 (file)
@@ -476,7 +476,7 @@ func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) {
                        return
                }
                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() {
                        buf.WriteString(" =")
index 7c33e7ade4095fcb3814836e4691f6882e308532..f4891df664abf77374ff453d437f22e0141f0171 100644 (file)
@@ -259,10 +259,9 @@ func instantiatedHash(typ *Named, targs []Type) string {
        assert(instanceHashing == 0)
        instanceHashing++
        var buf bytes.Buffer
-       writeTypeName(&buf, typ.obj, nil)
-       buf.WriteByte('[')
-       writeTypeList(&buf, targs, nil, nil)
-       buf.WriteByte(']')
+       w := newTypeWriter(&buf, nil)
+       w.typeName(typ.obj)
+       w.typeList(targs)
        instanceHashing--
 
        // With respect to the represented type, whether a
index c3befb077fc79d245d2a1aacd3526f92cc8ce46a..f313ea310e90d36e4a1a05e562fcdf1724402a18 100644 (file)
@@ -59,9 +59,7 @@ func (l *TypeList) String() string {
                return "[]"
        }
        var buf bytes.Buffer
-       buf.WriteByte('[')
-       writeTypeList(&buf, l.types, nil, nil)
-       buf.WriteByte(']')
+       newTypeWriter(&buf, nil).typeList(l.types)
        return buf.String()
 }
 
index 1775fc66773dd4cc5a408b25af8aced6ceae7381..d02f38a6ac49f5f890e0dee7e51e58b20cb01d3e 100644 (file)
@@ -52,79 +52,87 @@ func TypeString(typ Type, qf Qualifier) string {
 // The Qualifier controls the printing of
 // package-level objects, and may be nil.
 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
-// in "non-evaluated" instance form.
+// instanceMarker is the prefix for an instantiated type in unexpanded form.
 const instanceMarker = '#'
 
-func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []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 {
-                       fmt.Fprintf(buf, "○%T", goTypeName(typ)) // cycle to typ
-                       return
-               }
+type typeWriter struct {
+       buf  *bytes.Buffer
+       seen map[Type]bool
+       qf   Qualifier
+}
+
+func newTypeWriter(buf *bytes.Buffer, qf Qualifier) *typeWriter {
+       return &typeWriter{buf, make(map[Type]bool), qf}
+}
+
+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) {
        case nil:
-               buf.WriteString("<nil>")
+               w.string("<nil>")
 
        case *Basic:
                // exported basic types go into package unsafe
                // (currently this is just unsafe.Pointer)
                if isExported(t.name) {
                        if obj, _ := Unsafe.scope.Lookup(t.name).(*TypeName); obj != nil {
-                               writeTypeName(buf, obj, qf)
+                               w.typeName(obj)
                                break
                        }
                }
-               buf.WriteString(t.name)
+               w.string(t.name)
 
        case *Array:
-               fmt.Fprintf(buf, "[%d]", t.len)
-               writeType(buf, t.elem, qf, visited)
+               w.writef("[%d]", t.len)
+               w.typ(t.elem)
 
        case *Slice:
-               buf.WriteString("[]")
-               writeType(buf, t.elem, qf, visited)
+               w.string("[]")
+               w.typ(t.elem)
 
        case *Struct:
-               buf.WriteString("struct{")
+               w.string("struct{")
                for i, f := range t.fields {
                        if i > 0 {
-                               buf.WriteString("; ")
+                               w.string("; ")
                        }
                        // This doesn't do the right thing for embedded type
                        // aliases where we should print the alias name, not
                        // the aliased type (see issue #44410).
                        if !f.embedded {
-                               buf.WriteString(f.name)
-                               buf.WriteByte(' ')
+                               w.string(f.name)
+                               w.byte(' ')
                        }
-                       writeType(buf, f.typ, qf, visited)
+                       w.typ(f.typ)
                        if tag := t.Tag(i); tag != "" {
-                               fmt.Fprintf(buf, " %q", tag)
+                               w.writef(" %q", tag)
                        }
                }
-               buf.WriteByte('}')
+               w.byte('}')
 
        case *Pointer:
-               buf.WriteByte('*')
-               writeType(buf, t.base, qf, visited)
+               w.byte('*')
+               w.typ(t.base)
 
        case *Tuple:
-               writeTuple(buf, t, false, qf, visited)
+               w.tuple(t, false)
 
        case *Signature:
-               buf.WriteString("func")
-               writeSignature(buf, t, qf, visited)
+               w.string("func")
+               w.signature(t)
 
        case *Union:
                // 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 {
                        if i > 0 {
-                               buf.WriteByte('|')
+                               w.byte('|')
                        }
                        if t.tilde {
-                               buf.WriteByte('~')
+                               w.byte('~')
                        }
-                       writeType(buf, t.typ, qf, visited)
+                       w.typ(t.typ)
                }
 
        case *Interface:
-               buf.WriteString("interface{")
+               w.string("interface{")
                first := true
                for _, m := range t.methods {
                        if !first {
-                               buf.WriteString("; ")
+                               w.string("; ")
                        }
                        first = false
-                       buf.WriteString(m.name)
-                       writeSignature(buf, m.typ.(*Signature), qf, visited)
+                       w.string(m.name)
+                       w.signature(m.typ.(*Signature))
                }
                for _, typ := range t.embeddeds {
                        if !first {
-                               buf.WriteString("; ")
+                               w.string("; ")
                        }
                        first = false
-                       writeType(buf, typ, qf, visited)
+                       w.typ(typ)
                }
-               buf.WriteByte('}')
+               w.byte('}')
 
        case *Map:
-               buf.WriteString("map[")
-               writeType(buf, t.key, qf, visited)
-               buf.WriteByte(']')
-               writeType(buf, t.elem, qf, visited)
+               w.string("map[")
+               w.typ(t.key)
+               w.byte(']')
+               w.typ(t.elem)
 
        case *Chan:
                var s string
@@ -185,28 +193,26 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) {
                default:
                        unreachable()
                }
-               buf.WriteString(s)
+               w.string(s)
                if parens {
-                       buf.WriteByte('(')
+                       w.byte('(')
                }
-               writeType(buf, t.elem, qf, visited)
+               w.typ(t.elem)
                if parens {
-                       buf.WriteByte(')')
+                       w.byte(')')
                }
 
        case *Named:
                if t.instPos != nil {
-                       buf.WriteByte(instanceMarker)
+                       w.byte(instanceMarker)
                }
-               writeTypeName(buf, t.obj, qf)
+               w.typeName(t.obj)
                if t.targs != nil {
                        // instantiated type
-                       buf.WriteByte('[')
-                       writeTypeList(buf, t.targs.list(), qf, visited)
-                       buf.WriteByte(']')
+                       w.typeList(t.targs.list())
                } else if t.TParams().Len() != 0 {
                        // parameterized type
-                       writeTParamList(buf, t.TParams().list(), qf, visited)
+                       w.tParamList(t.TParams().list())
                }
 
        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
                        // for debugging purposes.
                        if t.obj.pkg != nil {
-                               writePackage(buf, t.obj.pkg, qf)
+                               writePackage(w.buf, t.obj.pkg, w.qf)
                        }
                        s = t.obj.name
                }
-               buf.WriteString(s + subscript(t.id))
+               w.string(s + subscript(t.id))
 
        case *top:
-               buf.WriteString("⊤")
+               w.string("⊤")
 
        default:
                // For externally defined implementations of Type.
                // 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 {
                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) {
-       buf.WriteString("[")
+func (w *typeWriter) tParamList(list []*TypeParam) {
+       w.byte('[')
        var prev Type
        for i, tpar := range list {
                // 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 bound != prev {
                                // bound changed - write previous one before advancing
-                               buf.WriteByte(' ')
-                               writeType(buf, prev, qf, visited)
+                               w.byte(' ')
+                               w.typ(prev)
                        }
-                       buf.WriteString(", ")
+                       w.string(", ")
                }
                prev = bound
 
                if tpar != nil {
-                       writeType(buf, tpar, qf, visited)
+                       w.typ(tpar)
                } else {
-                       buf.WriteString(tpar.obj.name)
+                       w.string(tpar.obj.name)
                }
        }
        if prev != nil {
-               buf.WriteByte(' ')
-               writeType(buf, prev, qf, visited)
+               w.byte(' ')
+               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 {
                assert(instanceHashing == 0) // we need an object for instance hashing
-               buf.WriteString("<Named w/o object>")
+               w.string("<Named w/o object>")
                return
        }
        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 {
                // 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 {
                        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.
 // If a scope is nil or has no parent (such as a package scope), nothing
 // is written.
-func writeScopeNumbers(buf *bytes.Buffer, s *Scope) {
+func (w *typeWriter) writeScopeNumbers(s *Scope) {
        if s != nil && s.number > 0 {
-               writeScopeNumbers(buf, s.parent)
-               fmt.Fprintf(buf, ".%d", s.number)
+               w.writeScopeNumbers(s.parent)
+               w.writef(".%d", s.number)
        }
 }
 
-func writeTuple(buf *bytes.Buffer, tup *Tuple, variadic bool, qf Qualifier, visited []Type) {
-       buf.WriteByte('(')
+func (w *typeWriter) tuple(tup *Tuple, variadic bool) {
+       w.byte('(')
        if tup != nil {
                for i, v := range tup.vars {
                        if i > 0 {
-                               buf.WriteString(", ")
+                               w.string(", ")
                        }
                        if v.name != "" {
-                               buf.WriteString(v.name)
-                               buf.WriteByte(' ')
+                               w.string(v.name)
+                               w.byte(' ')
                        }
                        typ := v.typ
                        if variadic && i == len(tup.vars)-1 {
                                if s, ok := typ.(*Slice); ok {
-                                       buf.WriteString("...")
+                                       w.string("...")
                                        typ = s.elem
                                } else {
                                        // 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 {
                                                panic("expected string type")
                                        }
-                                       writeType(buf, typ, qf, visited)
-                                       buf.WriteString("...")
+                                       w.typ(typ)
+                                       w.string("...")
                                        continue
                                }
                        }
-                       writeType(buf, typ, qf, visited)
+                       w.typ(typ)
                }
        }
-       buf.WriteByte(')')
+       w.byte(')')
 }
 
 // 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
 // package-level objects, and may be nil.
 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 {
-               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()
        if n == 0 {
@@ -367,15 +375,15 @@ func writeSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier, visited []T
                return
        }
 
-       buf.WriteByte(' ')
+       w.byte(' ')
        if n == 1 && sig.results.vars[0].name == "" {
                // single unnamed result
-               writeType(buf, sig.results.vars[0].typ, qf, visited)
+               w.typ(sig.results.vars[0].typ)
                return
        }
 
        // 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.
index 72542e7d2ed88329bed84fd0abd969d631059c6d..9eb1f63090986112db3856013ca8aef6ecabc36f 100644 (file)
@@ -76,16 +76,17 @@ type tparamsList struct {
 // String returns a string representation for a tparamsList. For debugging.
 func (d *tparamsList) String() string {
        var buf bytes.Buffer
-       buf.WriteByte('[')
+       w := newTypeWriter(&buf, nil)
+       w.byte('[')
        for i, tpar := range d.tparams {
                if i > 0 {
-                       buf.WriteString(", ")
+                       w.string(", ")
                }
-               writeType(&buf, tpar, nil, nil)
-               buf.WriteString(": ")
-               writeType(&buf, d.at(i), nil, nil)
+               w.typ(tpar)
+               w.string(": ")
+               w.typ(d.at(i))
        }
-       buf.WriteByte(']')
+       w.byte(']')
        return buf.String()
 }