From c7f11917cb9729a0dbe91f07206f2e12864fa550 Mon Sep 17 00:00:00 2001 From: David Chase Date: Mon, 1 Aug 2022 10:23:05 -0400 Subject: [PATCH] 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 Reviewed-by: Matthew Dempsky Run-TryBot: David Chase gopls-CI: kokoro --- go/internal/gcimporter/ureader_yes.go | 47 +++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/go/internal/gcimporter/ureader_yes.go b/go/internal/gcimporter/ureader_yes.go index 3c1a437543..add7bf8e3e 100644 --- a/go/internal/gcimporter/ureader_yes.go +++ b/go/internal/gcimporter/ureader_yes.go @@ -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) })