diff --git a/go/internal/gcimporter/bexport_test.go b/go/internal/gcimporter/bexport_test.go index 116a009cfc..7300ba8929 100644 --- a/go/internal/gcimporter/bexport_test.go +++ b/go/internal/gcimporter/bexport_test.go @@ -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()) diff --git a/go/internal/gcimporter/iexport_go118_test.go b/go/internal/gcimporter/iexport_go118_test.go index 50ac0f752d..b3617170ec 100644 --- a/go/internal/gcimporter/iexport_go118_test.go +++ b/go/internal/gcimporter/iexport_go118_test.go @@ -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)) } diff --git a/internal/typeparams/typeparams_go117.go b/internal/typeparams/typeparams_go117.go index 5a536526c5..214eab6667 100644 --- a/internal/typeparams/typeparams_go117.go +++ b/internal/typeparams/typeparams_go117.go @@ -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 { diff --git a/internal/typeparams/typeparams_go118.go b/internal/typeparams/typeparams_go118.go index e3c48221dd..55c0398e62 100644 --- a/internal/typeparams/typeparams_go118.go +++ b/internal/typeparams/typeparams_go118.go @@ -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 {