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())