Skip to content

Commit

Permalink
go/internal/gcimporter: allow reusing empty interfaces on the RHS of
Browse files Browse the repository at this point in the history
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 <[email protected]>
Run-TryBot: Robert Findley <[email protected]>
gopls-CI: kokoro <[email protected]>
TryBot-Result: Go Bot <[email protected]>
Reviewed-by: Robert Griesemer <[email protected]>
  • Loading branch information
findleyr committed Dec 1, 2021
1 parent d99d6fa commit df48029
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 2 deletions.
3 changes: 3 additions & 0 deletions go/internal/gcimporter/iexport_go118_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"}
Expand Down
22 changes: 20 additions & 2 deletions go/internal/gcimporter/iimport.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand All @@ -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
Expand Down

0 comments on commit df48029

Please sign in to comment.