1
0
mirror of https://github.com/golang/go synced 2024-11-26 09:38:10 -07:00

go/types: eliminate typeHashing global variable

This is a port of CL 345929 to go/types. It is also a step toward making
instantiation concurrency-safe.

Also fix some whitespace in instantiate.go.

Updates #47910

Change-Id: Icdeb227cb83eee15da6db90daab294c8c55db601
Reviewed-on: https://go-review.googlesource.com/c/go/+/346557
Trust: Robert Findley <rfindley@google.com>
Run-TryBot: Robert Findley <rfindley@google.com>
Reviewed-by: Robert Griesemer <gri@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
This commit is contained in:
Robert Findley 2021-08-31 18:15:53 -04:00
parent 0df6df17e1
commit 5cd1b847dc
3 changed files with 19 additions and 18 deletions

View File

@ -121,8 +121,8 @@ func (check *Checker) instance(pos token.Pos, typ Type, targs []Type) Type {
case *Named: case *Named:
h := typeHash(t, targs) h := typeHash(t, targs)
if check != nil { if check != nil {
// typ may already have been instantiated with identical type arguments. In // typ may already have been instantiated with identical type arguments.
// that case, re-use the existing instance. // In that case, re-use the existing instance.
if named := check.typMap[h]; named != nil { if named := check.typMap[h]; named != nil {
return named return named
} }
@ -135,6 +135,7 @@ func (check *Checker) instance(pos token.Pos, typ Type, targs []Type) Type {
check.typMap[h] = named check.typMap[h] = named
} }
return named return named
case *Signature: case *Signature:
tparams := t.TParams() tparams := t.TParams()
if !check.validateTArgLen(pos, tparams.Len(), len(targs)) { if !check.validateTArgLen(pos, tparams.Len(), len(targs)) {

View File

@ -256,8 +256,6 @@ func (subst *subster) typ(typ Type) Type {
return typ return typ
} }
var typeHashing = 0
// typeHash returns a string representation of typ, which can be used as an exact // typeHash returns a string representation of typ, which can be used as an exact
// type hash: types that are identical produce identical string representations. // type hash: types that are identical produce identical string representations.
// If typ is a *Named type and targs is not empty, typ is printed as if it were // If typ is a *Named type and targs is not empty, typ is printed as if it were
@ -266,19 +264,16 @@ func typeHash(typ Type, targs []Type) string {
assert(typ != nil) assert(typ != nil)
var buf bytes.Buffer var buf bytes.Buffer
assert(typeHashing == 0) h := newTypeHasher(&buf)
typeHashing++
w := newTypeWriter(&buf, nil)
if named, _ := typ.(*Named); named != nil && len(targs) > 0 { if named, _ := typ.(*Named); named != nil && len(targs) > 0 {
// Don't use WriteType because we need to use the provided targs // Don't use WriteType because we need to use the provided targs
// and not any targs that might already be with the *Named type. // and not any targs that might already be with the *Named type.
w.typeName(named.obj) h.typeName(named.obj)
w.typeList(targs) h.typeList(targs)
} else { } else {
assert(targs == nil) assert(targs == nil)
w.typ(typ) h.typ(typ)
} }
typeHashing--
if debug { if debug {
// there should be no instance markers in type hashes // there should be no instance markers in type hashes

View File

@ -63,10 +63,15 @@ type typeWriter struct {
buf *bytes.Buffer buf *bytes.Buffer
seen map[Type]bool seen map[Type]bool
qf Qualifier qf Qualifier
hash bool
} }
func newTypeWriter(buf *bytes.Buffer, qf Qualifier) *typeWriter { func newTypeWriter(buf *bytes.Buffer, qf Qualifier) *typeWriter {
return &typeWriter{buf, make(map[Type]bool), qf} return &typeWriter{buf, make(map[Type]bool), qf, false}
}
func newTypeHasher(buf *bytes.Buffer) *typeWriter {
return &typeWriter{buf, make(map[Type]bool), nil, true}
} }
func (w *typeWriter) byte(b byte) { w.buf.WriteByte(b) } func (w *typeWriter) byte(b byte) { w.buf.WriteByte(b) }
@ -208,7 +213,7 @@ func (w *typeWriter) typ(typ Type) {
// types. Write them to aid debugging, but don't write // types. Write them to aid debugging, but don't write
// them when we need an instance hash: whether a type // them when we need an instance hash: whether a type
// is fully expanded or not doesn't matter for identity. // is fully expanded or not doesn't matter for identity.
if typeHashing == 0 && t.instPos != nil { if !w.hash && t.instPos != nil {
w.byte(instanceMarker) w.byte(instanceMarker)
} }
w.typeName(t.obj) w.typeName(t.obj)
@ -292,7 +297,7 @@ func (w *typeWriter) tParamList(list []*TypeParam) {
func (w *typeWriter) typeName(obj *TypeName) { func (w *typeWriter) typeName(obj *TypeName) {
if obj == nil { if obj == nil {
assert(typeHashing == 0) // we need an object for type hashing assert(!w.hash) // we need an object for type hashing
w.string("<Named w/o object>") w.string("<Named w/o object>")
return return
} }
@ -301,7 +306,7 @@ func (w *typeWriter) typeName(obj *TypeName) {
} }
w.string(obj.name) w.string(obj.name)
if typeHashing != 0 { if w.hash {
// For local defined types, use the (original!) TypeName's scope // For local defined types, use the (original!) TypeName's scope
// numbers to disambiguate. // numbers to disambiguate.
if typ, _ := obj.typ.(*Named); typ != nil { if typ, _ := obj.typ.(*Named); typ != nil {
@ -335,7 +340,7 @@ func (w *typeWriter) tuple(tup *Tuple, variadic bool) {
w.string(", ") w.string(", ")
} }
// parameter names are ignored for type identity and thus type hashes // parameter names are ignored for type identity and thus type hashes
if typeHashing == 0 && v.name != "" { if !w.hash && v.name != "" {
w.string(v.name) w.string(v.name)
w.byte(' ') w.byte(' ')
} }
@ -383,8 +388,8 @@ func (w *typeWriter) signature(sig *Signature) {
} }
w.byte(' ') w.byte(' ')
if n == 1 && (typeHashing != 0 || sig.results.vars[0].name == "") { if n == 1 && (w.hash || sig.results.vars[0].name == "") {
// single unnamed result (if typeHashing, name must be ignored) // single unnamed result (if type hashing, name must be ignored)
w.typ(sig.results.vars[0].typ) w.typ(sig.results.vars[0].typ)
return return
} }