]> Cypherpunks.ru repositories - gostls13.git/blobdiff - src/cmd/compile/internal/types2/typestring.go
go/types, types2: introduce _Alias type node
[gostls13.git] / src / cmd / compile / internal / types2 / typestring.go
index 19f253c41e21bce937f05f608651b7260a5dfd47..3c2150273ee85c54276cea8d1af37c9b710afb35 100644 (file)
@@ -58,9 +58,8 @@ func WriteType(buf *bytes.Buffer, typ Type, qf Qualifier) {
 }
 
 // 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.
+// 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)
 }
@@ -73,15 +72,16 @@ type typeWriter struct {
        tparams      *TypeParamList // local type parameters
        paramNames   bool           // if set, write function parameter names, otherwise, write types only
        tpSubscripts bool           // if set, write type parameter indices as subscripts
+       pkgInfo      bool           // package-annotate first unexported-type field to avoid confusing type description
 }
 
 func newTypeWriter(buf *bytes.Buffer, qf Qualifier) *typeWriter {
-       return &typeWriter{buf, make(map[Type]bool), qf, nil, nil, true, false}
+       return &typeWriter{buf, make(map[Type]bool), qf, nil, nil, true, false, false}
 }
 
 func newTypeHasher(buf *bytes.Buffer, ctxt *Context) *typeWriter {
        assert(ctxt != nil)
-       return &typeWriter{buf, make(map[Type]bool), nil, ctxt, nil, false, false}
+       return &typeWriter{buf, make(map[Type]bool), nil, ctxt, nil, false, false, false}
 }
 
 func (w *typeWriter) byte(b byte) {
@@ -148,14 +148,29 @@ func (w *typeWriter) typ(typ Type) {
                        if i > 0 {
                                w.byte(';')
                        }
+
+                       // If disambiguating one struct for another, look for the first unexported field.
+                       // Do this first in case of nested structs; tag the first-outermost field.
+                       pkgAnnotate := false
+                       if w.qf == nil && w.pkgInfo && !isExported(f.name) {
+                               // note for embedded types, type name is field name, and "string" etc are lower case hence unexported.
+                               pkgAnnotate = true
+                               w.pkgInfo = false // only tag once
+                       }
+
                        // 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).
+                       // the aliased type (see go.dev/issue/44410).
                        if !f.embedded {
                                w.string(f.name)
                                w.byte(' ')
                        }
                        w.typ(f.typ)
+                       if pkgAnnotate {
+                               w.string(" /* package ")
+                               w.string(f.pkg.Path())
+                               w.string(" */ ")
+                       }
                        if tag := t.Tag(i); tag != "" {
                                w.byte(' ')
                                // TODO(gri) If tag contains blanks, replacing them with '#'
@@ -203,7 +218,7 @@ func (w *typeWriter) typ(typ Type) {
                                w.string("any")
                                break
                        }
-                       if t == universeComparable.Type().(*Named).underlying {
+                       if t == asNamed(universeComparable.Type()).underlying {
                                w.string("interface{comparable}")
                                break
                        }
@@ -302,6 +317,22 @@ func (w *typeWriter) typ(typ Type) {
                        if w.tpSubscripts || w.ctxt != nil {
                                w.string(subscript(t.id))
                        }
+                       // If the type parameter name is the same as a predeclared object
+                       // (say int), point out where it is declared to avoid confusing
+                       // error messages. This doesn't need to be super-elegant; we just
+                       // need a clear indication that this is not a predeclared name.
+                       if w.ctxt == nil && Universe.Lookup(t.obj.name) != nil {
+                               w.string(fmt.Sprintf(" /* with %s declared at %s */", t.obj.name, t.obj.Pos()))
+                       }
+               }
+
+       case *_Alias:
+               w.typeName(t.obj)
+               if w.ctxt != nil {
+                       // TODO(gri) do we need to print the alias type name, too?
+                       w.typ(_Unalias(t.obj.typ))
+               } else {
+                       w.string(fmt.Sprintf(" /* = %s */", _Unalias(t.obj.typ)))
                }
 
        default:
@@ -388,9 +419,7 @@ func (w *typeWriter) tParamList(list []*TypeParam) {
 }
 
 func (w *typeWriter) typeName(obj *TypeName) {
-       if obj.pkg != nil {
-               writePackage(w.buf, obj.pkg, w.qf)
-       }
+       w.string(packagePrefix(obj.pkg, w.qf))
        w.string(obj.name)
 }