}
// 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)
}
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) {
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 '#'
w.string("any")
break
}
- if t == universeComparable.Type().(*Named).underlying {
+ if t == asNamed(universeComparable.Type()).underlying {
w.string("interface{comparable}")
break
}
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:
}
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)
}