go/internal/gcimporter: set underlying types in proper order; flatten imports

These are copied from go/internal, for processing
export data from unified IR compilation.

The underlying types order problem appeared in google-internal
testing. If the run-later functions are run in the wrong order,
type definitions won't resolve properly.

Flatten imports makes the unified IR export/import match the
behavior of export data from older compilers, though it's not
clear that this behavior was intended, it is now expected.

See https://go.dev/cl/419996 and https://go.dev/cl/419596

Change-Id: I4197fe9e93ee07eb7f24597ba9157ce083a1d086
Reviewed-on: https://go-review.googlesource.com/c/tools/+/420534
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
Run-TryBot: David Chase <drchase@google.com>
gopls-CI: kokoro <noreply+kokoro@google.com>
This commit is contained in:
David Chase 2022-08-01 10:23:05 -04:00
parent bd3f524777
commit c7f11917cb
1 changed files with 45 additions and 2 deletions

View File

@ -36,6 +36,8 @@ type pkgReader struct {
// laterFns holds functions that need to be invoked at the end of
// import reading.
laterFns []func()
// laterFors is used in case of 'type A B' to ensure that B is processed before A.
laterFors map[types.Type]int
}
// later adds a function to be invoked at the end of import reading.
@ -63,6 +65,15 @@ func UImportData(fset *token.FileSet, imports map[string]*types.Package, data []
return
}
// laterFor adds a function to be invoked at the end of import reading, and records the type that function is finishing.
func (pr *pkgReader) laterFor(t types.Type, fn func()) {
if pr.laterFors == nil {
pr.laterFors = make(map[types.Type]int)
}
pr.laterFors[t] = len(pr.laterFns)
pr.laterFns = append(pr.laterFns, fn)
}
// readUnifiedPackage reads a package description from the given
// unified IR export data decoder.
func readUnifiedPackage(fset *token.FileSet, ctxt *types.Context, imports map[string]*types.Package, input pkgbits.PkgDecoder) *types.Package {
@ -231,11 +242,35 @@ func (r *reader) doPkg() *types.Package {
for i := range imports {
imports[i] = r.pkg()
}
pkg.SetImports(imports)
pkg.SetImports(flattenImports(imports))
return pkg
}
// flattenImports returns the transitive closure of all imported
// packages rooted from pkgs.
func flattenImports(pkgs []*types.Package) []*types.Package {
var res []*types.Package
seen := make(map[*types.Package]bool)
var add func(pkg *types.Package)
add = func(pkg *types.Package) {
if seen[pkg] {
return
}
seen[pkg] = true
res = append(res, pkg)
for _, imp := range pkg.Imports() {
add(imp)
}
}
for _, pkg := range pkgs {
add(pkg)
}
return res
}
// @@@ Types
func (r *reader) typ() types.Type {
@ -482,7 +517,15 @@ func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types.Package, string) {
// unit tests expected that), but cmd/compile doesn't care
// about it, so maybe we can avoid worrying about that here.
rhs := r.typ()
r.p.later(func() {
pk := r.p
pk.laterFor(named, func() {
// First be sure that the rhs is initialized, if it needs to be initialized.
delete(pk.laterFors, named) // prevent cycles
if i, ok := pk.laterFors[rhs]; ok {
f := pk.laterFns[i]
pk.laterFns[i] = func() {} // function is running now, so replace it with a no-op
f() // initialize RHS
}
underlying := rhs.Underlying()
named.SetUnderlying(underlying)
})