mirror of https://github.com/golang/go.git
[dev.go2go] go/types: prevent comparable interface from being used outside constraints
It was already not possible to implement an interface that was or embedded the predeclared interface "comparable" in ordinary (non- constraint) use, but trying to do so would lead to confusing errors (missing method "=="). Simply disallow the use of such interfaces outside constraints, as we do for interfaces containing type lists. Change-Id: I15ccf1b77226a50baf16df46192e90144208f9dd Reviewed-on: https://go-review.googlesource.com/c/go/+/238300 Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
parent
4ba19b0188
commit
c2b328710b
|
|
@ -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 */
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue