cmd/compile/internal/types2: when type hashing, use placeholders for type parameters

This is a port of CL 363114 from go/types to types2 with a temporary
work-around in tparamIndex to avoid a crash with the unified build
and test/typeparam/setsimp.go.

Change-Id: Id4805385f21c95b461911b246fb47ee278a84ac9
Reviewed-on: https://go-review.googlesource.com/c/go/+/364336
Trust: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
Robert Griesemer 2021-11-16 08:31:38 -08:00
parent a17a21c190
commit 489f58779c
2 changed files with 40 additions and 22 deletions

View File

@ -8,6 +8,7 @@ package types2
import (
"bytes"
"fmt"
"strconv"
"unicode/utf8"
)
@ -70,20 +71,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) {
@ -265,12 +267,16 @@ 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())
} else if w.ctxt == nil && t.TypeParams().Len() != 0 { // For type hashing, don't need to format the TParams
} else if w.ctxt == nil && t.TypeParams().Len() != 0 { // For type hashing, don't need to format the TypeParams
// parameterized type
w.tParamList(t.TypeParams().list())
}
@ -280,9 +286,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:
@ -292,15 +305,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 {
@ -385,6 +389,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())
}

View File

@ -9,6 +9,7 @@ package types2
import (
"bytes"
"fmt"
"internal/buildcfg"
)
// The unifier maintains two separate sets of type parameters x and y
@ -161,6 +162,12 @@ func (d *tparamsList) index(typ Type) int {
// If tpar is a type parameter in list, tparamIndex returns the type parameter index.
// Otherwise, the result is < 0. tpar must not be nil.
func tparamIndex(list []*TypeParam, tpar *TypeParam) int {
// Temporary work-around for getting around a crash
// with unified build.
// TODO(gri) investigate and implement proper fix
if buildcfg.Experiment.Unified && tpar.index < 0 {
return -1
}
if i := tpar.index; i < len(list) && list[i] == tpar {
return i
}