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>
diff --git a/go/internal/gcimporter/bexport_test.go b/go/internal/gcimporter/bexport_test.go
index 116a009..7300ba8 100644
--- a/go/internal/gcimporter/bexport_test.go
+++ b/go/internal/gcimporter/bexport_test.go
@@ -200,6 +200,9 @@
 				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 @@
 			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 @@
 	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())
diff --git a/go/internal/gcimporter/iexport_go118_test.go b/go/internal/gcimporter/iexport_go118_test.go
index 50ac0f7..b361717 100644
--- a/go/internal/gcimporter/iexport_go118_test.go
+++ b/go/internal/gcimporter/iexport_go118_test.go
@@ -36,6 +36,10 @@
 var IntID = ToInt[int]
 
 type G[C comparable] int
+
+func ImplicitFunc[T ~int]() {}
+
+type ImplicitType[T ~int] int
 `
 	testExportSrc(t, []byte(src))
 }
diff --git a/internal/typeparams/typeparams_go117.go b/internal/typeparams/typeparams_go117.go
index 5a53652..214eab6 100644
--- a/internal/typeparams/typeparams_go117.go
+++ b/internal/typeparams/typeparams_go117.go
@@ -132,6 +132,11 @@
 	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 {
diff --git a/internal/typeparams/typeparams_go118.go b/internal/typeparams/typeparams_go118.go
index e3c4822..55c0398 100644
--- a/internal/typeparams/typeparams_go118.go
+++ b/internal/typeparams/typeparams_go118.go
@@ -125,6 +125,11 @@
 	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 {