[dev.typeparams] cmd/compile: use Type.LinkString for map keys

This CL changes typecheck and order to use Type.LinkString for
computing map keys instead of Type.NameString. As mentioned in the
LinkString docs (added by the previous CL), LinkString reliably maps
type identity to string equality as long as the LinkString calls all
happen within the same compilation unit (which they do here).

This eliminates the need for subsequent types.Identical checks.

Change-Id: I32ff591e69d6f23f2dc6ebd5af343618ebe89013
Reviewed-on: https://go-review.googlesource.com/c/go/+/330911
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Trust: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
Matthew Dempsky 2021-06-25 10:15:40 -07:00
parent 942edc7502
commit ed647b16d0
3 changed files with 23 additions and 35 deletions

View File

@ -1388,7 +1388,7 @@ func WriteBasicTypes() {
type typeAndStr struct { type typeAndStr struct {
t *types.Type t *types.Type
short string short string // "short" here means NameString
regular string regular string
} }
@ -1401,8 +1401,13 @@ func (a typesByString) Less(i, j int) bool {
} }
// When the only difference between the types is whether // When the only difference between the types is whether
// they refer to byte or uint8, such as **byte vs **uint8, // they refer to byte or uint8, such as **byte vs **uint8,
// the types' ShortStrings can be identical. // the types' NameStrings can be identical.
// To preserve deterministic sort ordering, sort these by String(). // To preserve deterministic sort ordering, sort these by String().
//
// TODO(mdempsky): This all seems suspect. Using LinkString would
// avoid naming collisions, and there shouldn't be a reason to care
// about "byte" vs "uint8": they share the same runtime type
// descriptor anyway.
if a[i].regular != a[j].regular { if a[i].regular != a[j].regular {
return a[i].regular < a[j].regular return a[i].regular < a[j].regular
} }

View File

@ -662,29 +662,18 @@ func tcSwitchType(n *ir.SwitchStmt) {
} }
type typeSet struct { type typeSet struct {
m map[string][]typeSetEntry m map[string]src.XPos
}
type typeSetEntry struct {
pos src.XPos
typ *types.Type
} }
func (s *typeSet) add(pos src.XPos, typ *types.Type) { func (s *typeSet) add(pos src.XPos, typ *types.Type) {
if s.m == nil { if s.m == nil {
s.m = make(map[string][]typeSetEntry) s.m = make(map[string]src.XPos)
} }
// LongString does not uniquely identify types, so we need to ls := typ.LinkString()
// disambiguate collisions with types.Identical. if prev, ok := s.m[ls]; ok {
// TODO(mdempsky): Add a method that *is* unique. base.ErrorfAt(pos, "duplicate case %v in type switch\n\tprevious case at %s", typ, base.FmtPos(prev))
ls := typ.NameString() return
prevs := s.m[ls]
for _, prev := range prevs {
if types.Identical(typ, prev.typ) {
base.ErrorfAt(pos, "duplicate case %v in type switch\n\tprevious case at %s", typ, base.FmtPos(prev.pos))
return
}
} }
s.m[ls] = append(prevs, typeSetEntry{pos, typ}) s.m[ls] = pos
} }

View File

@ -51,7 +51,7 @@ import (
type orderState struct { type orderState struct {
out []ir.Node // list of generated statements out []ir.Node // list of generated statements
temp []*ir.Name // stack of temporary variables temp []*ir.Name // stack of temporary variables
free map[string][]*ir.Name // free list of unused temporaries, by type.LongString(). free map[string][]*ir.Name // free list of unused temporaries, by type.LinkString().
edit func(ir.Node) ir.Node // cached closure of o.exprNoLHS edit func(ir.Node) ir.Node // cached closure of o.exprNoLHS
} }
@ -76,20 +76,14 @@ func (o *orderState) append(stmt ir.Node) {
// If clear is true, newTemp emits code to zero the temporary. // If clear is true, newTemp emits code to zero the temporary.
func (o *orderState) newTemp(t *types.Type, clear bool) *ir.Name { func (o *orderState) newTemp(t *types.Type, clear bool) *ir.Name {
var v *ir.Name var v *ir.Name
// Note: LongString is close to the type equality we want, key := t.LinkString()
// but not exactly. We still need to double-check with types.Identical. if a := o.free[key]; len(a) > 0 {
key := t.NameString() v = a[len(a)-1]
a := o.free[key] if !types.Identical(t, v.Type()) {
for i, n := range a { base.Fatalf("expected %L to have type %v", v, t)
if types.Identical(t, n.Type()) {
v = a[i]
a[i] = a[len(a)-1]
a = a[:len(a)-1]
o.free[key] = a
break
} }
} o.free[key] = a[:len(a)-1]
if v == nil { } else {
v = typecheck.Temp(t) v = typecheck.Temp(t)
} }
if clear { if clear {
@ -370,7 +364,7 @@ func (o *orderState) markTemp() ordermarker {
// which must have been returned by markTemp. // which must have been returned by markTemp.
func (o *orderState) popTemp(mark ordermarker) { func (o *orderState) popTemp(mark ordermarker) {
for _, n := range o.temp[mark:] { for _, n := range o.temp[mark:] {
key := n.Type().NameString() key := n.Type().LinkString()
o.free[key] = append(o.free[key], n) o.free[key] = append(o.free[key], n)
} }
o.temp = o.temp[:mark] o.temp = o.temp[:mark]