[dev.typeparams] cmd/compile/internal/types2: implement package height

This CL extends types2 with package height information, styled after
the way it works already in cmd/compile:

- A new NewPackageHeight entry point for constructing packages with
  explicit height information, and a corresponding Height accessor
  method.

- The types2 importer is updated to provide package height for
  imported packages.

- The types2 type checker sets height based on imported packages.

- Adds an assertion to irgen to verify that types1 and types2
  calculated the same height for the source package.

- Func.less's ordering incorporates package height to match
  types.Sym.less and is generalized to object.less.

- sortTypes (used for sorting embedded types) now sorts defined types
  using object.less as well.

Change-Id: Id4dbbb627aef405cc7438d611cbdd5a5bd97fc96
Reviewed-on: https://go-review.googlesource.com/c/go/+/321231
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
Trust: Matthew Dempsky <mdempsky@google.com>
Trust: Robert Griesemer <gri@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
Matthew Dempsky 2021-05-18 19:03:00 -07:00
parent 3f6f12972b
commit eff66248ea
6 changed files with 76 additions and 41 deletions

View file

@ -118,17 +118,22 @@ func iImportData(imports map[string]*types2.Package, data []byte, path string) (
pkgPathOff := r.uint64()
pkgPath := p.stringAt(pkgPathOff)
pkgName := p.stringAt(r.uint64())
_ = r.uint64() // package height; unused by go/types
pkgHeight := int(r.uint64())
if pkgPath == "" {
pkgPath = path
}
pkg := imports[pkgPath]
if pkg == nil {
pkg = types2.NewPackage(pkgPath, pkgName)
pkg = types2.NewPackageHeight(pkgPath, pkgName, pkgHeight)
imports[pkgPath] = pkg
} else if pkg.Name() != pkgName {
errorf("conflicting names %s and %s for package %q", pkg.Name(), pkgName, path)
} else {
if pkg.Name() != pkgName {
errorf("conflicting names %s and %s for package %q", pkg.Name(), pkgName, path)
}
if pkg.Height() != pkgHeight {
errorf("conflicting heights %v and %v for package %q", pkg.Height(), pkgHeight, path)
}
}
p.pkgCache[pkgPathOff] = pkg

View file

@ -132,6 +132,7 @@ Outer:
}
}
}
assert(myheight == g.self.Height())
types.LocalPkg.Height = myheight
// 2. Process all package-block type declarations. As with imports,

View file

@ -186,6 +186,45 @@ func (obj *object) sameId(pkg *Package, name string) bool {
return pkg.path == obj.pkg.path
}
// less reports whether object a is ordered before object b.
//
// Objects are ordered nil before non-nil, exported before
// non-exported, then by name, and finally (for non-exported
// functions) by package height and path.
func (a *object) less(b *object) bool {
if a == b {
return false
}
// Nil before non-nil.
if a == nil {
return true
}
if b == nil {
return false
}
// Exported functions before non-exported.
ea := isExported(a.name)
eb := isExported(b.name)
if ea != eb {
return ea
}
// Order by name and then (for non-exported names) by package.
if a.name != b.name {
return a.name < b.name
}
if !ea {
if a.pkg.height != b.pkg.height {
return a.pkg.height < b.pkg.height
}
return a.pkg.path < b.pkg.path
}
return false
}
// A PkgName represents an imported Go package.
// PkgNames don't have a type.
type PkgName struct {
@ -329,36 +368,6 @@ func (obj *Func) FullName() string {
// Scope returns the scope of the function's body block.
func (obj *Func) Scope() *Scope { return obj.typ.(*Signature).scope }
// Less reports whether function a is ordered before function b.
//
// Functions are ordered exported before non-exported, then by name,
// and finally (for non-exported functions) by package path.
//
// TODO(gri) The compiler also sorts by package height before package
// path for non-exported names.
func (a *Func) less(b *Func) bool {
if a == b {
return false
}
// Exported functions before non-exported.
ea := isExported(a.name)
eb := isExported(b.name)
if ea != eb {
return ea
}
// Order by name and then (for non-exported names) by package.
if a.name != b.name {
return a.name < b.name
}
if !ea {
return a.pkg.path < b.pkg.path
}
return false
}
func (*Func) isDependency() {} // a function may be a dependency of an initialization expression
// A Label represents a declared label.

View file

@ -13,8 +13,9 @@ type Package struct {
path string
name string
scope *Scope
complete bool
imports []*Package
height int
complete bool
fake bool // scope lookup errors are silently dropped if package is fake (internal use only)
cgo bool // uses of this package will be rewritten into uses of declarations from _cgo_gotypes.go
}
@ -22,8 +23,14 @@ type Package struct {
// NewPackage returns a new Package for the given package path and name.
// The package is not complete and contains no explicit imports.
func NewPackage(path, name string) *Package {
return NewPackageHeight(path, name, 0)
}
// NewPackageHeight is like NewPackage, but allows specifying the
// package's height.
func NewPackageHeight(path, name string, height int) *Package {
scope := NewScope(Universe, nopos, nopos, fmt.Sprintf("package %q", path))
return &Package{path: path, name: name, scope: scope}
return &Package{path: path, name: name, scope: scope, height: height}
}
// Path returns the package path.
@ -32,6 +39,9 @@ func (pkg *Package) Path() string { return pkg.path }
// Name returns the package name.
func (pkg *Package) Name() string { return pkg.name }
// Height returns the package height.
func (pkg *Package) Height() int { return pkg.height }
// SetName sets the package name.
func (pkg *Package) SetName(name string) { pkg.name = name }

View file

@ -196,6 +196,7 @@ func (check *Checker) importPackage(pos syntax.Pos, path, dir string) *Package {
// methods with receiver base type names.
func (check *Checker) collectObjects() {
pkg := check.pkg
pkg.height = 0
// pkgImports is the set of packages already imported by any package file seen
// so far. Used to avoid duplicate entries in pkg.imports. Allocate and populate
@ -253,6 +254,15 @@ func (check *Checker) collectObjects() {
continue
}
if imp == Unsafe {
// typecheck ignores imports of package unsafe for
// calculating height.
// TODO(mdempsky): Revisit this. This seems fine, but I
// don't remember explicitly considering this case.
} else if h := imp.height + 1; h > pkg.height {
pkg.height = h
}
// local name overrides imported package name
name := imp.name
if s.LocalPkgName != nil {

View file

@ -1055,14 +1055,14 @@ func sortTypes(list []Type) {
type byUniqueTypeName []Type
func (a byUniqueTypeName) Len() int { return len(a) }
func (a byUniqueTypeName) Less(i, j int) bool { return sortName(a[i]) < sortName(a[j]) }
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 sortName(t Type) string {
func sortObj(t Type) *object {
if named := asNamed(t); named != nil {
return named.obj.Id()
return &named.obj.object
}
return ""
return nil
}
func sortMethods(list []*Func) {
@ -1082,7 +1082,7 @@ func assertSortedMethods(list []*Func) {
type byUniqueMethodName []*Func
func (a byUniqueMethodName) Len() int { return len(a) }
func (a byUniqueMethodName) Less(i, j int) bool { return a[i].less(a[j]) }
func (a byUniqueMethodName) Less(i, j int) bool { return a[i].less(&a[j].object) }
func (a byUniqueMethodName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (check *Checker) tag(t *syntax.BasicLit) string {