aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/types2/typestring.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/compile/internal/types2/typestring.go')
-rw-r--r--src/cmd/compile/internal/types2/typestring.go212
1 files changed, 83 insertions, 129 deletions
diff --git a/src/cmd/compile/internal/types2/typestring.go b/src/cmd/compile/internal/types2/typestring.go
index 40016697b7..cb7cf73a62 100644
--- a/src/cmd/compile/internal/types2/typestring.go
+++ b/src/cmd/compile/internal/types2/typestring.go
@@ -39,27 +39,6 @@ func RelativeTo(pkg *Package) Qualifier {
}
}
-// If gcCompatibilityMode is set, printing of types is modified
-// to match the representation of some types in the gc compiler:
-//
-// - byte and rune lose their alias name and simply stand for
-// uint8 and int32 respectively
-// - embedded interfaces get flattened (the embedding info is lost,
-// and certain recursive interface types cannot be printed anymore)
-//
-// This makes it easier to compare packages computed with the type-
-// checker vs packages imported from gc export data.
-//
-// Caution: This flag affects all uses of WriteType, globally.
-// It is only provided for testing in conjunction with
-// gc-generated data.
-//
-// This flag is exported in the x/tools/go/types package. We don't
-// need it at the moment in the std repo and so we don't export it
-// anymore. We should eventually try to remove it altogether.
-// TODO(gri) remove this
-var gcCompatibilityMode bool
-
// TypeString returns the string representation of typ.
// The Qualifier controls the printing of
// package-level objects, and may be nil.
@@ -106,16 +85,6 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) {
break
}
}
-
- if gcCompatibilityMode {
- // forget the alias names
- switch t.kind {
- case Byte:
- t = Typ[Uint8]
- case Rune:
- t = Typ[Int32]
- }
- }
buf.WriteString(t.name)
case *Array:
@@ -157,80 +126,39 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) {
buf.WriteString("func")
writeSignature(buf, t, qf, visited)
- case *Sum:
- for i, t := range t.types {
+ case *Union:
+ // Unions only appear as (syntactic) embedded elements
+ // in interfaces and syntactically cannot be empty.
+ if t.Len() == 0 {
+ panic("empty union")
+ }
+ for i, t := range t.terms {
if i > 0 {
- buf.WriteString(", ")
+ buf.WriteByte('|')
}
- writeType(buf, t, qf, visited)
+ if t.tilde {
+ buf.WriteByte('~')
+ }
+ writeType(buf, t.typ, qf, visited)
}
case *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 embedded
- // interface types that (directly or indirectly) embed the
- // current interface. For instance, consider the result type
- // of m:
- //
- // type T interface{
- // m() interface{ T }
- // }
- //
buf.WriteString("interface{")
- empty := true
- if gcCompatibilityMode {
- // print flattened interface
- // (useful to compare against gc-generated interfaces)
- for i, m := range t.allMethods {
- if i > 0 {
- buf.WriteString("; ")
- }
- buf.WriteString(m.name)
- writeSignature(buf, m.typ.(*Signature), qf, visited)
- empty = false
- }
- if !empty && t.allTypes != nil {
- buf.WriteString("; ")
- }
- if t.allTypes != nil {
- buf.WriteString("type ")
- writeType(buf, t.allTypes, qf, visited)
- }
- } else {
- // print explicit interface methods and embedded types
- for i, m := range t.methods {
- if i > 0 {
- buf.WriteString("; ")
- }
- buf.WriteString(m.name)
- writeSignature(buf, m.typ.(*Signature), qf, visited)
- empty = false
- }
- if !empty && t.types != nil {
+ first := true
+ for _, m := range t.methods {
+ if !first {
buf.WriteString("; ")
}
- if t.types != nil {
- buf.WriteString("type ")
- writeType(buf, t.types, qf, visited)
- empty = false
- }
- if !empty && len(t.embeddeds) > 0 {
- buf.WriteString("; ")
- }
- for i, typ := range t.embeddeds {
- if i > 0 {
- buf.WriteString("; ")
- }
- writeType(buf, typ, qf, visited)
- empty = false
- }
+ first = false
+ buf.WriteString(m.name)
+ writeSignature(buf, m.typ.(*Signature), qf, visited)
}
- if t.allMethods == nil || len(t.methods) > len(t.allMethods) {
- if !empty {
- buf.WriteByte(' ')
+ for _, typ := range t.embeddeds {
+ if !first {
+ buf.WriteString("; ")
}
- buf.WriteString("/* incomplete */")
+ first = false
+ writeType(buf, typ, qf, visited)
}
buf.WriteByte('}')
@@ -255,7 +183,7 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) {
case RecvOnly:
s = "<-chan "
default:
- panic("unreachable")
+ unreachable()
}
buf.WriteString(s)
if parens {
@@ -267,39 +195,40 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) {
}
case *Named:
+ if t.instance != nil {
+ buf.WriteByte(instanceMarker)
+ }
writeTypeName(buf, t.obj, qf)
if t.targs != nil {
// instantiated type
buf.WriteByte('[')
writeTypeList(buf, t.targs, qf, visited)
buf.WriteByte(']')
- } else if t.tparams != nil {
+ } else if t.TParams().Len() != 0 {
// parameterized type
- writeTParamList(buf, t.tparams, qf, visited)
+ writeTParamList(buf, t.TParams().list(), qf, visited)
}
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(buf, t.obj.pkg, qf)
+ }
s = t.obj.name
}
buf.WriteString(s + subscript(t.id))
- case *instance:
- buf.WriteByte(instanceMarker) // indicate "non-evaluated" syntactic instance
- writeTypeName(buf, t.base.obj, qf)
- buf.WriteByte('[')
- writeTypeList(buf, t.targs, qf, visited)
- buf.WriteByte(']')
-
- case *bottom:
- buf.WriteString("⊥")
-
case *top:
buf.WriteString("⊤")
default:
// For externally defined implementations of Type.
+ // Note: In this case cycles won't be caught.
buf.WriteString(t.String())
}
}
@@ -317,23 +246,27 @@ func writeTParamList(buf *bytes.Buffer, list []*TypeName, qf Qualifier, visited
buf.WriteString("[")
var prev Type
for i, p := range list {
- // TODO(gri) support 'any' sugar here.
- var b Type = &emptyInterface
- if t, _ := p.typ.(*TypeParam); t != nil && t.bound != nil {
- b = t.bound
+ // 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.
+ tpar, _ := p.typ.(*TypeParam)
+ var bound Type
+ if tpar != nil {
+ bound = tpar.bound // should not be nil but we want to see it if it is
}
+
if i > 0 {
- if b != prev {
- // type bound changed - write previous one before advancing
+ if bound != prev {
+ // bound changed - write previous one before advancing
buf.WriteByte(' ')
writeType(buf, prev, qf, visited)
}
buf.WriteString(", ")
}
- prev = b
+ prev = bound
- if t, _ := p.typ.(*TypeParam); t != nil {
- writeType(buf, t, qf, visited)
+ if tpar != nil {
+ writeType(buf, tpar, qf, visited)
} else {
buf.WriteString(p.name)
}
@@ -346,17 +279,38 @@ func writeTParamList(buf *bytes.Buffer, list []*TypeName, qf Qualifier, visited
}
func writeTypeName(buf *bytes.Buffer, obj *TypeName, qf Qualifier) {
- s := "<Named w/o object>"
- if obj != nil {
- if obj.pkg != nil {
- writePackage(buf, obj.pkg, qf)
+ if obj == nil {
+ buf.WriteString("<Named w/o object>")
+ return
+ }
+ if obj.pkg != nil {
+ writePackage(buf, obj.pkg, qf)
+ }
+ buf.WriteString(obj.name)
+
+ if instanceHashing != 0 {
+ // For local defined types, use the (original!) TypeName's scope
+ // numbers to disambiguate.
+ typ := obj.typ.(*Named)
+ // TODO(gri) Figure out why typ.orig != typ.orig.orig sometimes
+ // and whether the loop can iterate more than twice.
+ // (It seems somehow connected to instance types.)
+ for typ.orig != typ {
+ typ = typ.orig
}
- // TODO(gri): function-local named types should be displayed
- // differently from named types at package level to avoid
- // ambiguity.
- s = obj.name
+ writeScopeNumbers(buf, typ.obj.parent)
+ }
+}
+
+// writeScopeNumbers writes the number sequence for this scope to buf
+// 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) {
+ if s != nil && s.number > 0 {
+ writeScopeNumbers(buf, s.parent)
+ fmt.Fprintf(buf, ".%d", s.number)
}
- buf.WriteString(s)
}
func writeTuple(buf *bytes.Buffer, tup *Tuple, variadic bool, qf Qualifier, visited []Type) {
@@ -379,7 +333,7 @@ func writeTuple(buf *bytes.Buffer, tup *Tuple, variadic bool, qf Qualifier, visi
// special case:
// append(s, "foo"...) leads to signature func([]byte, string...)
if t := asBasic(typ); t == nil || t.kind != String {
- panic("internal error: string type expected")
+ panic("expected string type")
}
writeType(buf, typ, qf, visited)
buf.WriteString("...")
@@ -401,8 +355,8 @@ func WriteSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier) {
}
func writeSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier, visited []Type) {
- if sig.tparams != nil {
- writeTParamList(buf, sig.tparams, qf, visited)
+ if sig.TParams().Len() != 0 {
+ writeTParamList(buf, sig.TParams().list(), qf, visited)
}
writeTuple(buf, sig.params, sig.variadic, qf, visited)