From eff66248ea242c2611a9a0e2be47a762073e81b2 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Tue, 18 May 2021 19:03:00 -0700 Subject: [PATCH] [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 Trust: Matthew Dempsky Trust: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/importer/iimport.go | 13 ++-- src/cmd/compile/internal/noder/irgen.go | 1 + src/cmd/compile/internal/types2/object.go | 69 +++++++++++--------- src/cmd/compile/internal/types2/package.go | 14 +++- src/cmd/compile/internal/types2/resolver.go | 10 +++ src/cmd/compile/internal/types2/typexpr.go | 10 +-- 6 files changed, 76 insertions(+), 41 deletions(-) diff --git a/src/cmd/compile/internal/importer/iimport.go b/src/cmd/compile/internal/importer/iimport.go index 5c02f837ef4..b91b209d35e 100644 --- a/src/cmd/compile/internal/importer/iimport.go +++ b/src/cmd/compile/internal/importer/iimport.go @@ -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 diff --git a/src/cmd/compile/internal/noder/irgen.go b/src/cmd/compile/internal/noder/irgen.go index 3e0d3285ab9..2a9f0e99d8a 100644 --- a/src/cmd/compile/internal/noder/irgen.go +++ b/src/cmd/compile/internal/noder/irgen.go @@ -132,6 +132,7 @@ Outer: } } } + assert(myheight == g.self.Height()) types.LocalPkg.Height = myheight // 2. Process all package-block type declarations. As with imports, diff --git a/src/cmd/compile/internal/types2/object.go b/src/cmd/compile/internal/types2/object.go index 844bc34b6a3..8ed55f1dbf9 100644 --- a/src/cmd/compile/internal/types2/object.go +++ b/src/cmd/compile/internal/types2/object.go @@ -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. diff --git a/src/cmd/compile/internal/types2/package.go b/src/cmd/compile/internal/types2/package.go index 31b1e717877..c5804a05adc 100644 --- a/src/cmd/compile/internal/types2/package.go +++ b/src/cmd/compile/internal/types2/package.go @@ -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 } diff --git a/src/cmd/compile/internal/types2/resolver.go b/src/cmd/compile/internal/types2/resolver.go index ef49a8b48da..9b1482b14e1 100644 --- a/src/cmd/compile/internal/types2/resolver.go +++ b/src/cmd/compile/internal/types2/resolver.go @@ -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 { diff --git a/src/cmd/compile/internal/types2/typexpr.go b/src/cmd/compile/internal/types2/typexpr.go index a1663d2aa0c..7fb914cd7ec 100644 --- a/src/cmd/compile/internal/types2/typexpr.go +++ b/src/cmd/compile/internal/types2/typexpr.go @@ -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 {