diff --git a/src/go/types/examples/types.go2 b/src/go/types/examples/types.go2 index 4a4b997760..5358835582 100644 --- a/src/go/types/examples/types.go2 +++ b/src/go/types/examples/types.go2 @@ -249,7 +249,7 @@ func _(type A, B Adder, C Adder(A))() { } // The type of variables (incl. parameters and return values) cannot -// be an interface with type constraints. +// be an interface with type constraints or be/embed comparable. type I interface { type int } @@ -266,3 +266,17 @@ func _() I /* ERROR cannot contain type constraints */ func _() { var _ I /* ERROR cannot contain type constraints */ } + +type C interface { + comparable +} + +var _ comparable /* ERROR comparable */ +var _ C /* ERROR comparable */ + +func _(_ comparable /* ERROR comparable */ , _ C /* ERROR comparable */ ) + +func _() { + var _ comparable /* ERROR comparable */ + var _ C /* ERROR comparable */ +} \ No newline at end of file diff --git a/src/go/types/predicates.go b/src/go/types/predicates.go index 51193f2b41..d563f7f823 100644 --- a/src/go/types/predicates.go +++ b/src/go/types/predicates.go @@ -82,6 +82,17 @@ func IsInterface(typ Type) bool { return typ.Interface() != nil } +// isComparableInterface reports whether typ is an interface +// that is or embeds that predeclared interface "comparable". +func isComparableInterface(typ Type) bool { + // If the magic method == exists, the type parameter is comparable. + if t := typ.Interface(); t != nil { + _, m := lookupMethod(t.allMethods, nil, "==") + return m != nil + } + return false +} + // Comparable reports whether values of type T are comparable. func Comparable(T Type) bool { // If T is a type parameter not constraint by any type @@ -93,9 +104,7 @@ func Comparable(T Type) bool { // // is not comparable because []byte is not comparable. if t := T.TypeParam(); t != nil && optype(t) == theTop { - // If the magic method == exists, the type parameter is comparable. - _, m := lookupMethod(t.Bound().allMethods, nil, "==") - return m != nil + return isComparableInterface(t.Bound()) } switch t := optype(T.Under()).(type) { @@ -117,9 +126,7 @@ func Comparable(T Type) bool { case *Sum: return t.is(Comparable) case *TypeParam: - // If the magic method == exists, the type parameter is comparable. - _, m := lookupMethod(t.Bound().allMethods, nil, "==") - return m != nil + return isComparableInterface(t.Bound()) } return false } diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go index 5eb370282a..6cb9d9e313 100644 --- a/src/go/types/typexpr.go +++ b/src/go/types/typexpr.go @@ -136,6 +136,10 @@ func (check *Checker) varType(e ast.Expr) Type { check.completeInterface(e.Pos(), t) // TODO(gri) is this the correct position? if t.allTypes != nil { check.softErrorf(e.Pos(), "interface type for variable cannot contain type constraints (%s)", t.allTypes) + return + } + if isComparableInterface(t) { + check.softErrorf(e.Pos(), "interface type for variable cannot be (or embed) comparable") } }) }