From df48029e9bb85bff139da7f35f0194ae96b28a5a Mon Sep 17 00:00:00 2001 From: Robert Findley Date: Wed, 1 Dec 2021 13:55:45 -0500 Subject: [PATCH] go/internal/gcimporter: allow reusing empty interfaces on the RHS of type decls This is a port of CL 367851 to x/tools. The test set-up is slightly different; I added a TODO to converge. Updates golang/go#49888 Change-Id: I31a63c1fc8f9a78526d8eea05fd01dae35770b5f Reviewed-on: https://go-review.googlesource.com/c/tools/+/368354 Trust: Robert Findley Run-TryBot: Robert Findley gopls-CI: kokoro TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- go/internal/gcimporter/iexport_go118_test.go | 3 +++ go/internal/gcimporter/iimport.go | 22 ++++++++++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/go/internal/gcimporter/iexport_go118_test.go b/go/internal/gcimporter/iexport_go118_test.go index 2dc5cc143bb..5fc1f86169f 100644 --- a/go/internal/gcimporter/iexport_go118_test.go +++ b/go/internal/gcimporter/iexport_go118_test.go @@ -23,10 +23,13 @@ import ( "golang.org/x/tools/go/internal/gcimporter" ) +// TODO(rfindley): migrate this to testdata, as has been done in the standard library. func TestGenericExport(t *testing.T) { const src = ` package generic +type Any any + type T[A, B any] struct { Left A; Right B } var X T[int, string] = T[int, string]{1, "hi"} diff --git a/go/internal/gcimporter/iimport.go b/go/internal/gcimporter/iimport.go index 3e318749518..cdb332cd150 100644 --- a/go/internal/gcimporter/iimport.go +++ b/go/internal/gcimporter/iimport.go @@ -331,7 +331,7 @@ func (p *iimporter) pkgAt(off uint64) *types.Package { } func (p *iimporter) typAt(off uint64, base *types.Named) types.Type { - if t, ok := p.typCache[off]; ok && (base == nil || !isInterface(t)) { + if t, ok := p.typCache[off]; ok && canReuse(base, t) { return t } @@ -343,12 +343,30 @@ func (p *iimporter) typAt(off uint64, base *types.Named) types.Type { r.declReader.Reset(p.declData[off-predeclReserved:]) t := r.doType(base) - if base == nil || !isInterface(t) { + if canReuse(base, t) { p.typCache[off] = t } return t } +// canReuse reports whether the type rhs on the RHS of the declaration for def +// may be re-used. +// +// Specifically, if def is non-nil and rhs is an interface type with methods, it +// may not be re-used because we have a convention of setting the receiver type +// for interface methods to def. +func canReuse(def *types.Named, rhs types.Type) bool { + if def == nil { + return true + } + iface, _ := rhs.(*types.Interface) + if iface == nil { + return true + } + // Don't use iface.Empty() here as iface may not be complete. + return iface.NumEmbeddeds() == 0 && iface.NumExplicitMethods() == 0 +} + type importReader struct { p *iimporter declReader bytes.Reader