Skip to content

Commit

Permalink
go/internal/gcimporter: simplify unified IR importer
Browse files Browse the repository at this point in the history
CL 424854 changed the unified IR writer's handling of type
declarations to write the underlying type rather than the RHS type
expression's type. This in turn allows us to simplify the go/types
importer, because now there's no need to delay caling SetUnderlying.

Fixes #57015.

Change-Id: I80caa61f6cad5b7f9d829939db733a66cfca621c
Reviewed-on: https://go-review.googlesource.com/c/go/+/424876
Reviewed-by: Robert Griesemer <gri@google.com>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
  • Loading branch information
mdempsky committed Dec 7, 2022
1 parent dddc1ba commit a398963
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 45 deletions.
17 changes: 17 additions & 0 deletions src/go/internal/gcimporter/gcimporter_test.go
Expand Up @@ -787,6 +787,23 @@ func TestIssue25596(t *testing.T) {
compileAndImportPkg(t, "issue25596")
}

func TestIssue57015(t *testing.T) {
testenv.MustHaveGoBuild(t)

// This package only handles gc export data.
if runtime.Compiler != "gc" {
t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
}

// On windows, we have to set the -D option for the compiler to avoid having a drive
// letter and an illegal ':' in the import path - just skip it (see also issue #3483).
if runtime.GOOS == "windows" {
t.Skip("avoid dealing with relative paths/drive letters on windows")
}

compileAndImportPkg(t, "issue57015")
}

func importPkg(t *testing.T, path, srcDir string) *types.Package {
fset := token.NewFileSet()
pkg, err := Import(fset, make(map[string]*types.Package), path, srcDir, nil)
Expand Down
16 changes: 16 additions & 0 deletions src/go/internal/gcimporter/testdata/issue57015.go
@@ -0,0 +1,16 @@
// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package issue57015

type E error

type X[T any] struct {}

func F() X[interface {
E
}] {
panic(0)
}

68 changes: 23 additions & 45 deletions src/go/internal/gcimporter/ureader.go
Expand Up @@ -29,8 +29,6 @@ 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

// ifaces holds a list of constructed Interfaces, which need to have
// Complete called after importing is done.
Expand All @@ -42,15 +40,6 @@ func (pr *pkgReader) later(fn func()) {
pr.laterFns = append(pr.laterFns, fn)
}

// 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 {
Expand Down Expand Up @@ -538,43 +527,32 @@ func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types.Package, string) {

named.SetTypeParams(r.typeParamNames())

rhs := r.typ()
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 := r.typ().Underlying()

// If the underlying type is an interface, we need to
// duplicate its methods so we can replace the receiver
// parameter's type (#49906).
if iface, ok := underlying.(*types.Interface); ok && iface.NumExplicitMethods() != 0 {
methods := make([]*types.Func, iface.NumExplicitMethods())
for i := range methods {
fn := iface.ExplicitMethod(i)
sig := fn.Type().(*types.Signature)

recv := types.NewVar(fn.Pos(), fn.Pkg(), "", named)
methods[i] = types.NewFunc(fn.Pos(), fn.Pkg(), fn.Name(), types.NewSignature(recv, sig.Params(), sig.Results(), sig.Variadic()))
}
underlying := rhs.Underlying()

// If the underlying type is an interface, we need to
// duplicate its methods so we can replace the receiver
// parameter's type (#49906).
if iface, ok := underlying.(*types.Interface); ok && iface.NumExplicitMethods() != 0 {
methods := make([]*types.Func, iface.NumExplicitMethods())
for i := range methods {
fn := iface.ExplicitMethod(i)
sig := fn.Type().(*types.Signature)

recv := types.NewVar(fn.Pos(), fn.Pkg(), "", named)
methods[i] = types.NewFunc(fn.Pos(), fn.Pkg(), fn.Name(), types.NewSignature(recv, sig.Params(), sig.Results(), sig.Variadic()))
}

embeds := make([]types.Type, iface.NumEmbeddeds())
for i := range embeds {
embeds[i] = iface.EmbeddedType(i)
}

newIface := types.NewInterfaceType(methods, embeds)
r.p.ifaces = append(r.p.ifaces, newIface)
underlying = newIface

embeds := make([]types.Type, iface.NumEmbeddeds())
for i := range embeds {
embeds[i] = iface.EmbeddedType(i)
}

named.SetUnderlying(underlying)
})
newIface := types.NewInterfaceType(methods, embeds)
r.p.ifaces = append(r.p.ifaces, newIface)
underlying = newIface
}

named.SetUnderlying(underlying)

for i, n := 0, r.Len(); i < n; i++ {
named.AddMethod(r.method())
Expand Down

0 comments on commit a398963

Please sign in to comment.