]> Cypherpunks.ru repositories - gostls13.git/commitdiff
cmd/compile/internal/types2: more systematic error handling in typeWriter
authorRobert Griesemer <gri@golang.org>
Sun, 29 Aug 2021 17:57:06 +0000 (10:57 -0700)
committerRobert Griesemer <gri@golang.org>
Mon, 30 Aug 2021 22:07:53 +0000 (22:07 +0000)
When using a typeWriter for debugging/error message type strings,
it shouldn't crash in the presence of type-checker internal bugs.
But when a typeHasher is used, we don't want to silently ignore
errors.

Introduce an error method that panics in type hashing mode but
prints an error value otherwise.

Also fixed an incorrect 'if' statement in tParamList.

Change-Id: I26c8b8e0b14396e91ad71bf903e36ce1ca55839e
Reviewed-on: https://go-review.googlesource.com/c/go/+/346009
Trust: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
src/cmd/compile/internal/types2/typestring.go

index 3582d183a8ed3d8796b81f74ab3db8ae69799080..204e20c7ffd860beaa433ea442bada98ab77e9b3 100644 (file)
@@ -55,6 +55,14 @@ func WriteType(buf *bytes.Buffer, typ Type, qf Qualifier) {
        newTypeWriter(buf, qf).typ(typ)
 }
 
+// WriteSignature writes the representation of the signature sig to buf,
+// without a leading "func" keyword.
+// The Qualifier controls the printing of
+// package-level objects, and may be nil.
+func WriteSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier) {
+       newTypeWriter(buf, qf).signature(sig)
+}
+
 // instanceMarker is the prefix for an instantiated type in unexpanded form.
 const instanceMarker = '#'
 
@@ -76,10 +84,16 @@ func newTypeHasher(buf *bytes.Buffer) *typeWriter {
 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) error(msg string) {
+       if w.hash {
+               panic(msg)
+       }
+       w.string("<" + msg + ">")
+}
 
 func (w *typeWriter) typ(typ Type) {
        if w.seen[typ] {
-               w.writef("○%T", goTypeName(typ)) // cycle to typ
+               w.error("cycle to " + goTypeName(typ))
                return
        }
        w.seen[typ] = true
@@ -87,7 +101,7 @@ func (w *typeWriter) typ(typ Type) {
 
        switch t := typ.(type) {
        case nil:
-               w.string("<nil>")
+               w.error("nil")
 
        case *Basic:
                // exported basic types go into package unsafe
@@ -143,7 +157,8 @@ func (w *typeWriter) typ(typ Type) {
                // Unions only appear as (syntactic) embedded elements
                // in interfaces and syntactically cannot be empty.
                if t.Len() == 0 {
-                       panic("empty union")
+                       w.error("empty union")
+                       break
                }
                for i, t := range t.terms {
                        if i > 0 {
@@ -196,7 +211,8 @@ func (w *typeWriter) typ(typ Type) {
                case RecvOnly:
                        s = "<-chan "
                default:
-                       unreachable()
+                       w.error("unknown channel direction")
+                       break
                }
                w.string(s)
                if parens {
@@ -225,21 +241,21 @@ func (w *typeWriter) typ(typ Type) {
                }
 
        case *TypeParam:
-               s := "?"
-               if t.obj != nil {
-                       // Optionally write out package for typeparams (like Named).
-                       // TODO(danscales): this is required for import/export, so
-                       // we maybe need a separate function that won't be changed
-                       // for debugging purposes.
-                       if t.obj.pkg != nil {
-                               writePackage(w.buf, t.obj.pkg, w.qf)
-                       }
-                       s = t.obj.name
+               if t.obj == nil {
+                       w.error("unnamed type parameter")
+                       break
                }
-               w.string(s + subscript(t.id))
+               // Optionally write out package for typeparams (like Named).
+               // TODO(danscales): this is required for import/export, so
+               // we maybe need a separate function that won't be changed
+               // for debugging purposes.
+               if t.obj.pkg != nil {
+                       writePackage(w.buf, t.obj.pkg, w.qf)
+               }
+               w.string(t.obj.name + subscript(t.id))
 
        case *top:
-               w.string("⊤")
+               w.error("⊤")
 
        default:
                // For externally defined implementations of Type.
@@ -266,26 +282,20 @@ func (w *typeWriter) tParamList(list []*TypeParam) {
                // Determine the type parameter and its constraint.
                // list is expected to hold type parameter names,
                // but don't crash if that's not the case.
-               var bound Type
-               if tpar != nil {
-                       bound = tpar.bound // should not be nil but we want to see it if it is
+               if tpar == nil {
+                       w.error("nil type parameter")
+                       continue
                }
-
                if i > 0 {
-                       if bound != prev {
+                       if tpar.bound != prev {
                                // bound changed - write previous one before advancing
                                w.byte(' ')
                                w.typ(prev)
                        }
                        w.string(", ")
                }
-               prev = bound
-
-               if tpar != nil {
-                       w.typ(tpar)
-               } else {
-                       w.string(tpar.obj.name)
-               }
+               prev = tpar.bound
+               w.typ(tpar)
        }
        if prev != nil {
                w.byte(' ')
@@ -295,11 +305,6 @@ func (w *typeWriter) tParamList(list []*TypeParam) {
 }
 
 func (w *typeWriter) typeName(obj *TypeName) {
-       if obj == nil {
-               assert(!w.hash) // we need an object for type hashing
-               w.string("<Named w/o object>")
-               return
-       }
        if obj.pkg != nil {
                writePackage(w.buf, obj.pkg, w.qf)
        }
@@ -352,7 +357,8 @@ func (w *typeWriter) tuple(tup *Tuple, variadic bool) {
                                        // special case:
                                        // append(s, "foo"...) leads to signature func([]byte, string...)
                                        if t := asBasic(typ); t == nil || t.kind != String {
-                                               panic("expected string type")
+                                               w.error("expected string type")
+                                               continue
                                        }
                                        w.typ(typ)
                                        w.string("...")
@@ -365,14 +371,6 @@ func (w *typeWriter) tuple(tup *Tuple, variadic bool) {
        w.byte(')')
 }
 
-// WriteSignature writes the representation of the signature sig to buf,
-// without a leading "func" keyword.
-// The Qualifier controls the printing of
-// package-level objects, and may be nil.
-func WriteSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier) {
-       newTypeWriter(buf, qf).signature(sig)
-}
-
 func (w *typeWriter) signature(sig *Signature) {
        if sig.TParams().Len() != 0 {
                w.tParamList(sig.TParams().list())