go/types: when type hashing, use placeholders for type parameters

Type parameter names don't matter for the purposes of generic type
identity, so mask them with numeric placeholders when hashing.

Change-Id: Iacb4c23abecdd733fc292ae13ecac6baa2c5524c
Reviewed-on: https://go-review.googlesource.com/c/go/+/363114
Trust: Robert Findley <rfindley@google.com>
Run-TryBot: Robert Findley <rfindley@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
Robert Findley 2021-11-10 15:53:16 -05:00
parent bfbe5ac9ce
commit c97d6817a3
1 changed files with 32 additions and 21 deletions

View File

@ -8,6 +8,7 @@ package types
import (
"bytes"
"fmt"
"go/token"
"strconv"
"unicode/utf8"
@ -71,20 +72,21 @@ func WriteSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier) {
}
type typeWriter struct {
buf *bytes.Buffer
seen map[Type]bool
qf Qualifier
ctxt *Context // if non-nil, we are type hashing
debug bool // if true, write debug annotations
buf *bytes.Buffer
seen map[Type]bool
qf Qualifier
ctxt *Context // if non-nil, we are type hashing
tparams *TypeParamList // local type parameters
debug bool // if true, write debug annotations
}
func newTypeWriter(buf *bytes.Buffer, qf Qualifier) *typeWriter {
return &typeWriter{buf, make(map[Type]bool), qf, nil, false}
return &typeWriter{buf, make(map[Type]bool), qf, nil, nil, false}
}
func newTypeHasher(buf *bytes.Buffer, ctxt *Context) *typeWriter {
assert(ctxt != nil)
return &typeWriter{buf, make(map[Type]bool), nil, ctxt, false}
return &typeWriter{buf, make(map[Type]bool), nil, ctxt, nil, false}
}
func (w *typeWriter) byte(b byte) {
@ -259,8 +261,12 @@ func (w *typeWriter) typ(typ Type) {
}
case *Named:
w.typePrefix(t)
w.typeName(t.obj)
// If hashing, write a unique prefix for t to represent its identity, since
// named type identity is pointer identity.
if w.ctxt != nil {
w.string(strconv.Itoa(w.ctxt.getID(t)))
}
w.typeName(t.obj) // when hashing written for readability of the hash only
if t.targs != nil {
// instantiated type
w.typeList(t.targs.list())
@ -274,9 +280,16 @@ func (w *typeWriter) typ(typ Type) {
w.error("unnamed type parameter")
break
}
w.string(t.obj.name)
if w.debug || w.ctxt != nil {
w.string(subscript(t.id))
if i := tparamIndex(w.tparams.list(), t); i >= 0 {
// The names of type parameters that are declared by the type being
// hashed are not part of the type identity. Replace them with a
// placeholder indicating their index.
w.string(fmt.Sprintf("$%d", i))
} else {
w.string(t.obj.name)
if w.debug || w.ctxt != nil {
w.string(subscript(t.id))
}
}
default:
@ -286,15 +299,6 @@ func (w *typeWriter) typ(typ Type) {
}
}
// If w.ctxt is non-nil, typePrefix writes a unique prefix for the named type t
// based on the types already observed by w.ctxt. If w.ctxt is nil, it does
// nothing.
func (w *typeWriter) typePrefix(t *Named) {
if w.ctxt != nil {
w.string(strconv.Itoa(w.ctxt.getID(t)))
}
}
func (w *typeWriter) typeList(list []Type) {
w.byte('[')
for i, typ := range list {
@ -379,6 +383,13 @@ func (w *typeWriter) tuple(tup *Tuple, variadic bool) {
func (w *typeWriter) signature(sig *Signature) {
if sig.TypeParams().Len() != 0 {
if w.ctxt != nil {
assert(w.tparams == nil)
w.tparams = sig.TypeParams()
defer func() {
w.tparams = nil
}()
}
w.tParamList(sig.TypeParams().list())
}