// If T is comparable, V must be comparable.
// Remember as a pending error and report only if we don't have a more specific error.
var pending error
- if Ti.IsComparable() && !Comparable(V) {
+ if Ti.IsComparable() && ((Vi != nil && !Vi.IsComparable()) || (Vi == nil && !Comparable(V))) {
pending = errorf("%s does not implement comparable", V)
}
t.Errorf("comparable is not a comparable type")
}
- // TODO(gri) should comparable be an alias, like any? (see #50791)
- if !Implements(anyType, comparableType.Underlying().(*Interface)) {
- t.Errorf("any does not implement comparable")
+ if Implements(anyType, comparableType.Underlying().(*Interface)) {
+ t.Errorf("any implements comparable")
}
if !Implements(comparableType, anyType.(*Interface)) {
t.Errorf("comparable does not implement any")
}
- if !AssignableTo(anyType, comparableType) {
- t.Errorf("any not assignable to comparable")
+ if AssignableTo(anyType, comparableType) {
+ t.Errorf("any assignable to comparable")
}
if !AssignableTo(comparableType, anyType) {
t.Errorf("comparable not assignable to any")
if y, ok := y.(*Interface); ok {
xset := x.typeSet()
yset := y.typeSet()
+ if xset.comparable != yset.comparable {
+ return false
+ }
if !xset.terms.equal(yset.terms) {
return false
}
import "io"
import "context"
-// Interfaces are always comparable (though the comparison may panic at runtime).
func eql[T comparable](x, y T) bool {
return x == y
}
-func _() {
- var x interface{}
- var y interface{ m() }
+func _[X comparable, Y interface{comparable; m()}]() {
+ var x X
+ var y Y
eql(x, y /* ERROR does not match */ ) // interfaces of different types
eql(x, x)
eql(y, y)
- eql(y, nil)
- eql[io.Reader](nil, nil)
+ eql(y, nil /* ERROR cannot use nil as Y value in argument to eql */ )
+ eql[io /* ERROR does not implement comparable */ .Reader](nil, nil)
}
// If we have a receiver of pointer to type parameter type (below: *T)
package p
-// Because we can use == and != with values of arbitrary
-// interfaces, all interfaces implement comparable.
-
func f1[_ comparable]() {}
func f2[_ interface{ comparable }]() {}
func _[P comparable, Q ~int, R any]() {
_ = f1[int]
- _ = f1[T]
- _ = f1[any]
+ _ = f1[T /* ERROR T does not implement comparable */ ]
+ _ = f1[any /* ERROR any does not implement comparable */ ]
_ = f1[P]
_ = f1[Q]
_ = f1[R /* ERROR R does not implement comparable */]
_ = f2[int]
- _ = f2[T]
- _ = f2[any]
+ _ = f2[T /* ERROR T does not implement comparable */ ]
+ _ = f2[any /* ERROR any does not implement comparable */ ]
_ = f2[P]
_ = f2[Q]
_ = f2[R /* ERROR R does not implement comparable */]
if y, ok := y.(*Interface); ok {
xset := x.typeSet()
yset := y.typeSet()
+ if xset.comparable != yset.comparable {
+ return false
+ }
if !xset.terms.equal(yset.terms) {
return false
}
// If T is comparable, V must be comparable.
// Remember as a pending error and report only if we don't have a more specific error.
var pending error
- if Ti.IsComparable() && !Comparable(V) {
+ if Ti.IsComparable() && ((Vi != nil && !Vi.IsComparable()) || (Vi == nil && !Comparable(V))) {
pending = errorf("%s does not implement comparable", V)
}
t.Errorf("comparable is not a comparable type")
}
- // TODO(gri) should comparable be an alias, like any? (see #50791)
- if !Implements(anyType, comparableType.Underlying().(*Interface)) {
- t.Errorf("any does not implement comparable")
+ if Implements(anyType, comparableType.Underlying().(*Interface)) {
+ t.Errorf("any implements comparable")
}
if !Implements(comparableType, anyType.(*Interface)) {
t.Errorf("comparable does not implement any")
}
- if !AssignableTo(anyType, comparableType) {
- t.Errorf("any not assignable to comparable")
+ if AssignableTo(anyType, comparableType) {
+ t.Errorf("any assignable to comparable")
}
if !AssignableTo(comparableType, anyType) {
t.Errorf("comparable not assignable to any")
if y, ok := y.(*Interface); ok {
xset := x.typeSet()
yset := y.typeSet()
+ if xset.comparable != yset.comparable {
+ return false
+ }
if !xset.terms.equal(yset.terms) {
return false
}
import "io"
import "context"
-// Interfaces are always comparable (though the comparison may panic at runtime).
func eql[T comparable](x, y T) bool {
return x == y
}
-func _() {
- var x interface{}
- var y interface{ m() }
+func _[X comparable, Y interface{comparable; m()}]() {
+ var x X
+ var y Y
eql(x, y /* ERROR does not match */ ) // interfaces of different types
eql(x, x)
eql(y, y)
- eql(y, nil)
- eql[io.Reader](nil, nil)
+ eql(y, nil /* ERROR cannot use nil as Y value in argument to eql */ )
+ eql[io /* ERROR does not implement comparable */ .Reader](nil, nil)
}
// If we have a receiver of pointer to type parameter type (below: *T)
package p
-// Because we can use == and != with values of arbitrary
-// interfaces, all interfaces implement comparable.
-
func f1[_ comparable]() {}
func f2[_ interface{ comparable }]() {}
func _[P comparable, Q ~int, R any]() {
_ = f1[int]
- _ = f1[T]
- _ = f1[any]
+ _ = f1[T /* ERROR T does not implement comparable */ ]
+ _ = f1[any /* ERROR any does not implement comparable */ ]
_ = f1[P]
_ = f1[Q]
_ = f1[R /* ERROR R does not implement comparable */]
_ = f2[int]
- _ = f2[T]
- _ = f2[any]
+ _ = f2[T /* ERROR T does not implement comparable */ ]
+ _ = f2[any /* ERROR any does not implement comparable */ ]
_ = f2[P]
_ = f2[Q]
_ = f2[R /* ERROR R does not implement comparable */]
if y, ok := y.(*Interface); ok {
xset := x.typeSet()
yset := y.typeSet()
+ if xset.comparable != yset.comparable {
+ return false
+ }
if !xset.terms.equal(yset.terms) {
return false
}
import "fmt"
func main() {
- IsZero[interface{}]("")
+ IsZero[int](0)
}
func IsZero[T comparable](val T) bool {
+++ /dev/null
-// run -gcflags=-G=3
-
-// Copyright 2022 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package main
-
-func eql[P comparable](x, y P) {
- if x != y {
- panic("not equal")
- }
-}
-
-func expectPanic(f func()) {
- defer func() {
- if recover() == nil {
- panic("function succeeded unexpectedly")
- }
- }()
- f()
-}
-
-func main() {
- eql[int](1, 1)
- eql(1, 1)
-
- // all interfaces implement comparable
- var x, y any = 2, 2
- eql[any](x, y)
- eql(x, y)
-
- // but we may get runtime panics
- x, y = 1, 2 // x != y
- expectPanic(func() { eql(x, y) })
-
- x, y = main, main // functions are not comparable
- expectPanic(func() { eql(x, y) })
-}