diff options
| author | hopehook <hopehook.com@gmail.com> | 2022-10-07 22:42:15 +0800 |
|---|---|---|
| committer | Gopher Robot <gobot@golang.org> | 2022-10-17 14:53:58 +0000 |
| commit | 7ffc1e47b4e3b163f06fc33c9adbc29cb1622d47 (patch) | |
| tree | a12106d1c0daf4b24fedb21a161a2c1f7b8d3401 | |
| parent | 9abcc487f8b04db8fd46eaa429a7eef5a5228241 (diff) | |
| download | go-7ffc1e47b4e3b163f06fc33c9adbc29cb1622d47.tar.xz | |
reflect: panic when Value.Equal using two non-comparable values
Assuming the two values are valid and non-comparable, Equal should panic.
x := reflect.ValueOf([]int{1, 2, 3})
x.Equal(x) // can not report false, should panic
Assuming one of them is non-comparable and the other is invalid, it should
always report false.
x := reflect.ValueOf([]int{1, 2, 3})
y := reflect.ValueOf(nil)
x.Equal(y) // should report false
For #46746.
Change-Id: Ifecd77ca0b3de3019fae2be39048f9277831676c
Reviewed-on: https://go-review.googlesource.com/c/go/+/440037
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: David Chase <drchase@google.com>
Run-TryBot: Ian Lance Taylor <iant@google.com>
Auto-Submit: Ian Lance Taylor <iant@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
| -rw-r--r-- | src/reflect/all_test.go | 50 | ||||
| -rw-r--r-- | src/reflect/value.go | 5 |
2 files changed, 38 insertions, 17 deletions
diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go index 40377178a5..e5d0b2c07c 100644 --- a/src/reflect/all_test.go +++ b/src/reflect/all_test.go @@ -8245,16 +8245,6 @@ var valueEqualTests = []ValueEqualTest{ true, false, }, { - &equalSlice, []int{1}, - false, - true, false, - }, - { - map[int]int{}, map[int]int{}, - false, - false, false, - }, - { (chan int)(nil), nil, false, false, false, @@ -8289,11 +8279,6 @@ var valueEqualTests = []ValueEqualTest{ true, false, false, }, - { - &mapInterface, &mapInterface, - false, - true, true, - }, } func TestValue_Equal(t *testing.T) { @@ -8324,6 +8309,41 @@ func TestValue_Equal(t *testing.T) { } } +func TestValue_EqualNonComparable(t *testing.T) { + var invalid = Value{} // ValueOf(nil) + var values = []Value{ + // Value of slice is non-comparable. + ValueOf([]int(nil)), + ValueOf(([]int{})), + + // Value of map is non-comparable. + ValueOf(map[int]int(nil)), + ValueOf((map[int]int{})), + + // Value of func is non-comparable. + ValueOf(((func())(nil))), + ValueOf(func() {}), + + // Value of struct is non-comparable because of non-comparable elements. + ValueOf((NonComparableStruct{})), + + // Value of array is non-comparable because of non-comparable elements. + ValueOf([0]map[int]int{}), + ValueOf([0]func(){}), + ValueOf(([1]struct{ I interface{} }{{[]int{}}})), + ValueOf(([1]interface{}{[1]interface{}{map[int]int{}}})), + } + for _, value := range values { + // Panic when reflect.Value.Equal using two valid non-comparable values. + shouldPanic("reflect.Value.Equal using two non-comparable values", func() { value.Equal(value) }) + + // If one is non-comparable and the other is invalid, the expected result is always false. + if r := value.Equal(invalid); r != false { + t.Errorf("%s == invalid got %t, want false", value.Type(), r) + } + } +} + func TestInitFuncTypes(t *testing.T) { n := 100 var wg sync.WaitGroup diff --git a/src/reflect/value.go b/src/reflect/value.go index eeee6fac0f..448ffa2058 100644 --- a/src/reflect/value.go +++ b/src/reflect/value.go @@ -3320,7 +3320,8 @@ func (v Value) Comparable() bool { } // Equal reports true if v is equal to u. -// For valid values, if either v or u is non-comparable, Equal returns false. +// For valid values, if one of them is non-comparable, and the other is comparable, +// Equal reports false; if v and u are both non-comparable, Equal will panic. func (v Value) Equal(u Value) bool { if !v.IsValid() || !u.IsValid() { return v.IsValid() == u.IsValid() @@ -3334,7 +3335,7 @@ func (v Value) Equal(u Value) bool { return v.Elem().Equal(u.Elem()) } - return false + panic("reflect.Value.Equal using two non-comparable values") } // convertOp returns the function to convert a value of type src |
