go/internal/gcimporter: normalize implicit interfaces in export tests

The export data format does not yet support capturing whether interfaces
are implicit, so normalize them for the purposes of comparing type
parameter constraints.

Change-Id: I678fb5f5fe6481b9a1479176ca056a31d17bbd77
Reviewed-on: https://go-review.googlesource.com/c/tools/+/355971
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: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
Robert Findley 2021-10-14 17:46:40 -04:00
parent 3a269dc41f
commit ce04ca3bf6
4 changed files with 40 additions and 3 deletions

View File

@ -200,6 +200,9 @@ func equalType(x, y types.Type) error {
return fmt.Errorf("mismatched %s method: %s", xm.Name(), err)
}
}
// Constraints are handled explicitly in the *TypeParam case below, so we
// don't yet need to consider embeddeds here.
// TODO(rfindley): consider the type set here.
case *types.Array:
y := y.(*types.Array)
if x.Len() != y.Len() {
@ -315,9 +318,12 @@ func equalType(x, y types.Type) error {
return fmt.Errorf("unequal named types: %s vs %s", x, y)
}
// For now, just compare constraints by type string to short-circuit
// cycles.
xc := sanitizeName(x.Constraint().String())
yc := sanitizeName(y.Constraint().String())
// cycles. We have to make interfaces explicit as export data currently
// doesn't support marking interfaces as implicit.
// TODO(rfindley): remove makeExplicit once export data contains an
// implicit bit.
xc := sanitizeName(makeExplicit(x.Constraint()).String())
yc := sanitizeName(makeExplicit(y.Constraint()).String())
if xc != yc {
return fmt.Errorf("unequal constraints: %s vs %s", xc, yc)
}
@ -328,6 +334,23 @@ func equalType(x, y types.Type) error {
return nil
}
// makeExplicit returns an explicit version of typ, if typ is an implicit
// interface. Otherwise it returns typ unmodified.
func makeExplicit(typ types.Type) types.Type {
if iface, _ := typ.(*types.Interface); iface != nil && typeparams.IsImplicit(iface) {
var methods []*types.Func
for i := 0; i < iface.NumExplicitMethods(); i++ {
methods = append(methods, iface.Method(i))
}
var embeddeds []types.Type
for i := 0; i < iface.NumEmbeddeds(); i++ {
embeddeds = append(embeddeds, iface.EmbeddedType(i))
}
return types.NewInterfaceType(methods, embeddeds)
}
return typ
}
func equalTypeArgs(x, y *typeparams.TypeList) error {
if x.Len() != y.Len() {
return fmt.Errorf("unequal lengths: %d vs %d", x.Len(), y.Len())

View File

@ -36,6 +36,10 @@ func ToInt[P interface{ ~int }](p P) int { return int(p) }
var IntID = ToInt[int]
type G[C comparable] int
func ImplicitFunc[T ~int]() {}
type ImplicitType[T ~int] int
`
testExportSrc(t, []byte(src))
}

View File

@ -132,6 +132,11 @@ func IsMethodSet(*types.Interface) bool {
return true
}
// IsImplicit returns false, as no interfaces are implicit at this Go version.
func IsImplicit(*types.Interface) bool {
return false
}
// ForNamed returns an empty type parameter list, as type parameters are not
// supported at this Go version.
func ForNamed(*types.Named) *TypeParamList {

View File

@ -125,6 +125,11 @@ func IsMethodSet(iface *types.Interface) bool {
return iface.IsMethodSet()
}
// IsImplicit calls iface.IsImplicit().
func IsImplicit(iface *types.Interface) bool {
return iface.IsImplicit()
}
// ForNamed extracts the (possibly empty) type parameter object list from
// named.
func ForNamed(named *types.Named) *TypeParamList {