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 <rfindley@google.com>
Run-TryBot: Robert Findley <rfindley@google.com>
gopls-CI: kokoro <noreply+kokoro@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
diff --git a/go/internal/gcimporter/iexport_go118_test.go b/go/internal/gcimporter/iexport_go118_test.go
index 2dc5cc1..5fc1f86 100644
--- a/go/internal/gcimporter/iexport_go118_test.go
+++ b/go/internal/gcimporter/iexport_go118_test.go
@@ -23,10 +23,13 @@
"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 3e31874..cdb332c 100644
--- a/go/internal/gcimporter/iimport.go
+++ b/go/internal/gcimporter/iimport.go
@@ -331,7 +331,7 @@
}
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 @@
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