[dev.typeparams] cmd/compile/internal/types2: move embedding positions from Checker to Interface

This change moves the position information to the place where it
is actually used. It also simplifies getting rid of it after use.

In the process, fixed a latent bug: Before this CL, embedded types
were sorted, but the corresponding embedding positions were not.
Removed the sorting altogether as it is not needed for type-checking.

Change-Id: I48003f317196d814326424430336b6cb222fdee6
Reviewed-on: https://go-review.googlesource.com/c/go/+/331514
Trust: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
Robert Griesemer 2021-06-28 17:21:26 -07:00
parent 1ff43d1b17
commit f0206e3df2
5 changed files with 28 additions and 43 deletions

View File

@ -82,12 +82,11 @@ type Checker struct {
conf *Config conf *Config
pkg *Package pkg *Package
*Info *Info
version version // accepted language version version version // accepted language version
nextID uint64 // unique Id for type parameters (first valid Id is 1) nextID uint64 // unique Id for type parameters (first valid Id is 1)
objMap map[Object]*declInfo // maps package-level objects and (non-interface) methods to declaration info objMap map[Object]*declInfo // maps package-level objects and (non-interface) methods to declaration info
impMap map[importKey]*Package // maps (import path, source directory) to (complete or fake) package impMap map[importKey]*Package // maps (import path, source directory) to (complete or fake) package
posMap map[*Interface][]syntax.Pos // maps interface types to lists of embedded interface positions typMap map[string]*Named // maps an instantiated named type hash to a *Named type
typMap map[string]*Named // maps an instantiated named type hash to a *Named type
// pkgPathMap maps package names to the set of distinct import paths we've // pkgPathMap maps package names to the set of distinct import paths we've
// seen for that name, anywhere in the import graph. It is used for // seen for that name, anywhere in the import graph. It is used for
@ -189,7 +188,6 @@ func NewChecker(conf *Config, pkg *Package, info *Info) *Checker {
version: version, version: version,
objMap: make(map[Object]*declInfo), objMap: make(map[Object]*declInfo),
impMap: make(map[importKey]*Package), impMap: make(map[importKey]*Package),
posMap: make(map[*Interface][]syntax.Pos),
typMap: make(map[string]*Named), typMap: make(map[string]*Named),
} }
} }

View File

@ -14,11 +14,18 @@ func (check *Checker) interfaceType(ityp *Interface, iface *syntax.InterfaceType
var tlist []syntax.Expr // types collected from all type lists var tlist []syntax.Expr // types collected from all type lists
var tname *syntax.Name // most recent "type" name var tname *syntax.Name // most recent "type" name
addEmbedded := func(pos syntax.Pos, typ Type) {
ityp.embeddeds = append(ityp.embeddeds, typ)
if ityp.embedPos == nil {
ityp.embedPos = new([]syntax.Pos)
}
*ityp.embedPos = append(*ityp.embedPos, pos)
}
for _, f := range iface.MethodList { for _, f := range iface.MethodList {
if f.Name == nil { if f.Name == nil {
// We have an embedded type; possibly a union of types. // We have an embedded type; possibly a union of types.
ityp.embeddeds = append(ityp.embeddeds, parseUnion(check, flattenUnion(nil, f.Type))) addEmbedded(f.Type.Pos(), parseUnion(check, flattenUnion(nil, f.Type)))
check.posMap[ityp] = append(check.posMap[ityp], f.Type.Pos())
continue continue
} }
// f.Name != nil // f.Name != nil
@ -89,10 +96,9 @@ func (check *Checker) interfaceType(ityp *Interface, iface *syntax.InterfaceType
// If we saw a type list, add it like an embedded union. // If we saw a type list, add it like an embedded union.
if tlist != nil { if tlist != nil {
ityp.embeddeds = append(ityp.embeddeds, parseUnion(check, tlist))
// Types T in a type list are added as ~T expressions but we don't // Types T in a type list are added as ~T expressions but we don't
// have the position of the '~'. Use the first type position instead. // have the position of the '~'. Use the first type position instead.
check.posMap[ityp] = append(check.posMap[ityp], tlist[0].(*syntax.Operation).X.Pos()) addEmbedded(tlist[0].(*syntax.Operation).X.Pos(), parseUnion(check, tlist))
} }
// All methods and embedded elements for this interface are collected; // All methods and embedded elements for this interface are collected;
@ -106,8 +112,8 @@ func (check *Checker) interfaceType(ityp *Interface, iface *syntax.InterfaceType
} }
// sort for API stability // sort for API stability
// (don't sort embeddeds: they must correspond to *embedPos entries)
sortMethods(ityp.methods) sortMethods(ityp.methods)
sortTypes(ityp.embeddeds)
// Compute type set with a non-nil *Checker as soon as possible // Compute type set with a non-nil *Checker as soon as possible
// to report any errors. Subsequent uses of type sets should be // to report any errors. Subsequent uses of type sets should be
@ -227,14 +233,13 @@ func newTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *TypeSet {
// collect embedded elements // collect embedded elements
var allTypes Type var allTypes Type
var posList []syntax.Pos
if check != nil {
posList = check.posMap[ityp]
}
for i, typ := range ityp.embeddeds { for i, typ := range ityp.embeddeds {
// The embedding position is nil for imported interfaces
// and also for interface copies after substitution (but
// in that case we don't need to report errors again).
var pos syntax.Pos // embedding position var pos syntax.Pos // embedding position
if posList != nil { if ityp.embedPos != nil {
pos = posList[i] pos = (*ityp.embedPos)[i]
} }
var types Type var types Type
switch t := under(typ).(type) { switch t := under(typ).(type) {
@ -268,6 +273,7 @@ func newTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *TypeSet {
} }
allTypes = intersect(allTypes, types) allTypes = intersect(allTypes, types)
} }
ityp.embedPos = nil // not needed anymore (errors have been reported)
// process todo's (this only happens if check == nil) // process todo's (this only happens if check == nil)
for i := 0; i < len(todo); i += 2 { for i := 0; i < len(todo); i += 2 {
@ -287,24 +293,6 @@ func newTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *TypeSet {
return ityp.tset return ityp.tset
} }
func sortTypes(list []Type) {
sort.Stable(byUniqueTypeName(list))
}
// byUniqueTypeName named type lists can be sorted by their unique type names.
type byUniqueTypeName []Type
func (a byUniqueTypeName) Len() int { return len(a) }
func (a byUniqueTypeName) Less(i, j int) bool { return sortObj(a[i]).less(sortObj(a[j])) }
func (a byUniqueTypeName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func sortObj(t Type) *object {
if named := asNamed(t); named != nil {
return &named.obj.object
}
return nil
}
func sortMethods(list []*Func) { func sortMethods(list []*Func) {
sort.Sort(byUniqueMethodName(list)) sort.Sort(byUniqueMethodName(list))
} }

View File

@ -28,7 +28,7 @@ func TestSizeof(t *testing.T) {
{Tuple{}, 12, 24}, {Tuple{}, 12, 24},
{Signature{}, 44, 88}, {Signature{}, 44, 88},
{Union{}, 24, 48}, {Union{}, 24, 48},
{Interface{}, 40, 80}, {Interface{}, 44, 88},
{Map{}, 16, 32}, {Map{}, 16, 32},
{Chan{}, 12, 24}, {Chan{}, 12, 24},
{Named{}, 84, 160}, {Named{}, 84, 160},

View File

@ -316,7 +316,6 @@ func (subst *subster) typ(typ Type) Type {
if subst.check == nil { if subst.check == nil {
panic("internal error: cannot instantiate interfaces yet") panic("internal error: cannot instantiate interfaces yet")
} }
subst.check.posMap[iface] = subst.check.posMap[t] // satisfy completeInterface requirement
return iface return iface
} }

View File

@ -264,10 +264,11 @@ func (s *Signature) Variadic() bool { return s.variadic }
// An Interface represents an interface type. // An Interface represents an interface type.
type Interface struct { type Interface struct {
obj Object // type name object defining this interface; or nil (for better error messages) obj Object // type name object defining this interface; or nil (for better error messages)
methods []*Func // ordered list of explicitly declared methods methods []*Func // ordered list of explicitly declared methods
embeddeds []Type // ordered list of explicitly embedded elements embeddeds []Type // ordered list of explicitly embedded elements
complete bool // indicates that obj, methods, and embeddeds are set and type set can be computed embedPos *[]syntax.Pos // positions of embedded elements; or nil (for error messages) - use pointer to save space
complete bool // indicates that all fields (except for tset) are set up
tset *TypeSet // type set described by this interface, computed lazily tset *TypeSet // type set described by this interface, computed lazily
} }
@ -322,7 +323,6 @@ func NewInterfaceType(methods []*Func, embeddeds []Type) *Interface {
// sort for API stability // sort for API stability
sortMethods(methods) sortMethods(methods)
sortTypes(embeddeds)
typ.methods = methods typ.methods = methods
typ.embeddeds = embeddeds typ.embeddeds = embeddeds