From 489f58779ce073ef8f6b1505f80580211200ff60 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Tue, 16 Nov 2021 08:31:38 -0800 Subject: [PATCH] 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 Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/typestring.go | 55 +++++++++++-------- src/cmd/compile/internal/types2/unify.go | 7 +++ 2 files changed, 40 insertions(+), 22 deletions(-) diff --git a/src/cmd/compile/internal/types2/typestring.go b/src/cmd/compile/internal/types2/typestring.go index 1857f58a4b..ba3494d9d9 100644 --- a/src/cmd/compile/internal/types2/typestring.go +++ b/src/cmd/compile/internal/types2/typestring.go @@ -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()) } diff --git a/src/cmd/compile/internal/types2/unify.go b/src/cmd/compile/internal/types2/unify.go index ccb6ee8709..651bba1a6b 100644 --- a/src/cmd/compile/internal/types2/unify.go +++ b/src/cmd/compile/internal/types2/unify.go @@ -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 } -- 2.50.0