Skip to content

Commit de81c9a

Browse files
committed
Auto merge of #22320 - petrochenkov:eq, r=alexcrichton
All types that are "slices in disguise" - `[T]`, `[T; N]`, `Vec<T>` etc and sometimes references to them (see #21725) should be equality comparable to each other. Many of them are already comparable, but some are not and this PR patches the holes in the impls of `PartialEq` for slice-like entities. Ideally, the problem could be solved by an impl roughly looking like ``` impl<T, U, A, B> PartialEq<U> for T where T: BorrowSlice<A>, U: BorrowSlice<B>, A: PartialEq<B> { fn eq(&self, other: &U) -> bool { self.borrow_slice() == other.borrow_slice() } fn ne(&self, other: &U) -> bool { self.borrow_slice() != other.borrow_slice() } } ``` , but the type system would never allow such a simple and obvious solution. Therefore, the patch follows this approach, but implements it with macros and not generics. The applied changes are conservative, in particular, the smart pointers aren't touched at all. But the comparisons for `Box<[T]>`, `Rc<[T]>` and `Arc<[T]>` seem trivial to add. (Should I do it?) This PR partially address #21725 Technically this is a [breaking-change], because the impls for fixed-size arrays are more conservative now. Note: There are blanket impls of `PartialEq` in libcore/cmp.rs (see https://github.com/rust-lang/rust/blob/master/src/libcore/cmp.rs#L432 and below), they strip an *equal* number of references from both operands and then compare the remains. It would be much better to strip *all* the references before the comparison in the blanket impls to reduce the number of concrete impls, but I haven't found a way to do it without specialization/negative bounds. r? @aturon cc @gankro
2 parents f0f7ca2 + 5e616db commit de81c9a

File tree

5 files changed

+86
-103
lines changed

5 files changed

+86
-103
lines changed

Diff for: src/libcollections/vec.rs

+24-59
Original file line numberDiff line numberDiff line change
@@ -1493,69 +1493,34 @@ impl<T> Extend<T> for Vec<T> {
14931493
}
14941494
}
14951495

1496-
impl<A, B> PartialEq<Vec<B>> for Vec<A> where A: PartialEq<B> {
1497-
#[inline]
1498-
fn eq(&self, other: &Vec<B>) -> bool { PartialEq::eq(&**self, &**other) }
1499-
#[inline]
1500-
fn ne(&self, other: &Vec<B>) -> bool { PartialEq::ne(&**self, &**other) }
1501-
}
1502-
1503-
macro_rules! impl_eq {
1504-
($lhs:ty, $rhs:ty) => {
1505-
impl<'b, A, B> PartialEq<$rhs> for $lhs where A: PartialEq<B> {
1506-
#[inline]
1507-
fn eq(&self, other: &$rhs) -> bool { PartialEq::eq(&**self, &**other) }
1508-
#[inline]
1509-
fn ne(&self, other: &$rhs) -> bool { PartialEq::ne(&**self, &**other) }
1510-
}
1511-
1512-
impl<'b, A, B> PartialEq<$lhs> for $rhs where B: PartialEq<A> {
1513-
#[inline]
1514-
fn eq(&self, other: &$lhs) -> bool { PartialEq::eq(&**self, &**other) }
1515-
#[inline]
1516-
fn ne(&self, other: &$lhs) -> bool { PartialEq::ne(&**self, &**other) }
1517-
}
1496+
__impl_slice_eq1! { Vec<A>, Vec<B> }
1497+
__impl_slice_eq2! { Vec<A>, &'b [B] }
1498+
__impl_slice_eq2! { Vec<A>, &'b mut [B] }
1499+
__impl_slice_eq2! { CowVec<'a, A>, &'b [B], Clone }
1500+
__impl_slice_eq2! { CowVec<'a, A>, &'b mut [B], Clone }
1501+
__impl_slice_eq2! { CowVec<'a, A>, Vec<B>, Clone }
1502+
1503+
macro_rules! array_impls {
1504+
($($N: expr)+) => {
1505+
$(
1506+
// NOTE: some less important impls are omitted to reduce code bloat
1507+
__impl_slice_eq2! { Vec<A>, [B; $N] }
1508+
__impl_slice_eq2! { Vec<A>, &'b [B; $N] }
1509+
// __impl_slice_eq2! { Vec<A>, &'b mut [B; $N] }
1510+
// __impl_slice_eq2! { CowVec<'a, A>, [B; $N], Clone }
1511+
// __impl_slice_eq2! { CowVec<'a, A>, &'b [B; $N], Clone }
1512+
// __impl_slice_eq2! { CowVec<'a, A>, &'b mut [B; $N], Clone }
1513+
)+
15181514
}
15191515
}
15201516

1521-
impl_eq! { Vec<A>, &'b [B] }
1522-
impl_eq! { Vec<A>, &'b mut [B] }
1523-
1524-
impl<'a, A, B> PartialEq<Vec<B>> for Cow<'a, [A]> where A: PartialEq<B> + Clone {
1525-
#[inline]
1526-
fn eq(&self, other: &Vec<B>) -> bool { PartialEq::eq(&**self, &**other) }
1527-
#[inline]
1528-
fn ne(&self, other: &Vec<B>) -> bool { PartialEq::ne(&**self, &**other) }
1517+
array_impls! {
1518+
0 1 2 3 4 5 6 7 8 9
1519+
10 11 12 13 14 15 16 17 18 19
1520+
20 21 22 23 24 25 26 27 28 29
1521+
30 31 32
15291522
}
15301523

1531-
impl<'a, A, B> PartialEq<Cow<'a, [A]>> for Vec<B> where A: Clone, B: PartialEq<A> {
1532-
#[inline]
1533-
fn eq(&self, other: &Cow<'a, [A]>) -> bool { PartialEq::eq(&**self, &**other) }
1534-
#[inline]
1535-
fn ne(&self, other: &Cow<'a, [A]>) -> bool { PartialEq::ne(&**self, &**other) }
1536-
}
1537-
1538-
macro_rules! impl_eq_for_cowvec {
1539-
($rhs:ty) => {
1540-
impl<'a, 'b, A, B> PartialEq<$rhs> for Cow<'a, [A]> where A: PartialEq<B> + Clone {
1541-
#[inline]
1542-
fn eq(&self, other: &$rhs) -> bool { PartialEq::eq(&**self, &**other) }
1543-
#[inline]
1544-
fn ne(&self, other: &$rhs) -> bool { PartialEq::ne(&**self, &**other) }
1545-
}
1546-
1547-
impl<'a, 'b, A, B> PartialEq<Cow<'a, [A]>> for $rhs where A: Clone, B: PartialEq<A> {
1548-
#[inline]
1549-
fn eq(&self, other: &Cow<'a, [A]>) -> bool { PartialEq::eq(&**self, &**other) }
1550-
#[inline]
1551-
fn ne(&self, other: &Cow<'a, [A]>) -> bool { PartialEq::ne(&**self, &**other) }
1552-
}
1553-
}
1554-
}
1555-
1556-
impl_eq_for_cowvec! { &'b [B] }
1557-
impl_eq_for_cowvec! { &'b mut [B] }
1558-
15591524
#[stable(feature = "rust1", since = "1.0.0")]
15601525
impl<T: PartialOrd> PartialOrd for Vec<T> {
15611526
#[inline]
@@ -2470,7 +2435,7 @@ mod tests {
24702435
fn test_into_boxed_slice() {
24712436
let xs = vec![1, 2, 3];
24722437
let ys = xs.into_boxed_slice();
2473-
assert_eq!(ys, [1, 2, 3]);
2438+
assert_eq!(&*ys, [1, 2, 3]);
24742439
}
24752440

24762441
#[test]

Diff for: src/libcore/array.rs

+8-43
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@ use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering};
1919
use fmt;
2020
use hash::{Hash, self};
2121
use iter::IntoIterator;
22-
use marker::Copy;
23-
use ops::Deref;
22+
use marker::{Copy, Sized};
2423
use option::Option;
2524
use slice::{Iter, IterMut, SliceExt};
2625

@@ -69,47 +68,13 @@ macro_rules! array_impls {
6968
}
7069
}
7170

72-
#[stable(feature = "rust1", since = "1.0.0")]
73-
impl<A, B> PartialEq<[B; $N]> for [A; $N] where A: PartialEq<B> {
74-
#[inline]
75-
fn eq(&self, other: &[B; $N]) -> bool {
76-
&self[..] == &other[..]
77-
}
78-
#[inline]
79-
fn ne(&self, other: &[B; $N]) -> bool {
80-
&self[..] != &other[..]
81-
}
82-
}
83-
84-
#[stable(feature = "rust1", since = "1.0.0")]
85-
impl<'a, A, B, Rhs> PartialEq<Rhs> for [A; $N] where
86-
A: PartialEq<B>,
87-
Rhs: Deref<Target=[B]>,
88-
{
89-
#[inline(always)]
90-
fn eq(&self, other: &Rhs) -> bool {
91-
PartialEq::eq(&self[..], &**other)
92-
}
93-
#[inline(always)]
94-
fn ne(&self, other: &Rhs) -> bool {
95-
PartialEq::ne(&self[..], &**other)
96-
}
97-
}
98-
99-
#[stable(feature = "rust1", since = "1.0.0")]
100-
impl<'a, A, B, Lhs> PartialEq<[B; $N]> for Lhs where
101-
A: PartialEq<B>,
102-
Lhs: Deref<Target=[A]>
103-
{
104-
#[inline(always)]
105-
fn eq(&self, other: &[B; $N]) -> bool {
106-
PartialEq::eq(&**self, &other[..])
107-
}
108-
#[inline(always)]
109-
fn ne(&self, other: &[B; $N]) -> bool {
110-
PartialEq::ne(&**self, &other[..])
111-
}
112-
}
71+
// NOTE: some less important impls are omitted to reduce code bloat
72+
__impl_slice_eq1! { [A; $N], [B; $N] }
73+
__impl_slice_eq2! { [A; $N], [B] }
74+
__impl_slice_eq2! { [A; $N], &'b [B] }
75+
__impl_slice_eq2! { [A; $N], &'b mut [B] }
76+
// __impl_slice_eq2! { [A; $N], &'b [B; $N] }
77+
// __impl_slice_eq2! { [A; $N], &'b mut [B; $N] }
11378

11479
#[stable(feature = "rust1", since = "1.0.0")]
11580
impl<T:Eq> Eq for [T; $N] { }

Diff for: src/libcore/cmp_macros.rs

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Utility macros for implementing PartialEq on slice-like types
12+
13+
#![doc(hidden)]
14+
15+
#[macro_export]
16+
macro_rules! __impl_slice_eq1 {
17+
($Lhs: ty, $Rhs: ty) => {
18+
#[stable(feature = "rust1", since = "1.0.0")]
19+
impl<'a, 'b, A, B> PartialEq<$Rhs> for $Lhs where A: PartialEq<B> {
20+
#[inline]
21+
fn eq(&self, other: &$Rhs) -> bool { &self[..] == &other[..] }
22+
#[inline]
23+
fn ne(&self, other: &$Rhs) -> bool { &self[..] != &other[..] }
24+
}
25+
}
26+
}
27+
28+
#[macro_export]
29+
macro_rules! __impl_slice_eq2 {
30+
($Lhs: ty, $Rhs: ty) => {
31+
__impl_slice_eq2! { $Lhs, $Rhs, Sized }
32+
};
33+
($Lhs: ty, $Rhs: ty, $Bound: ident) => {
34+
#[stable(feature = "rust1", since = "1.0.0")]
35+
impl<'a, 'b, A: $Bound, B> PartialEq<$Rhs> for $Lhs where A: PartialEq<B> {
36+
#[inline]
37+
fn eq(&self, other: &$Rhs) -> bool { &self[..] == &other[..] }
38+
#[inline]
39+
fn ne(&self, other: &$Rhs) -> bool { &self[..] != &other[..] }
40+
}
41+
42+
#[stable(feature = "rust1", since = "1.0.0")]
43+
impl<'a, 'b, A: $Bound, B> PartialEq<$Lhs> for $Rhs where B: PartialEq<A> {
44+
#[inline]
45+
fn eq(&self, other: &$Lhs) -> bool { &self[..] == &other[..] }
46+
#[inline]
47+
fn ne(&self, other: &$Lhs) -> bool { &self[..] != &other[..] }
48+
}
49+
}
50+
}

Diff for: src/libcore/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@
7272
#[macro_use]
7373
mod macros;
7474

75+
#[macro_use]
76+
mod cmp_macros;
77+
7578
#[path = "num/float_macros.rs"]
7679
#[macro_use]
7780
mod float_macros;

Diff for: src/libstd/ffi/c_str.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,7 @@ impl CStr {
371371

372372
impl PartialEq for CStr {
373373
fn eq(&self, other: &CStr) -> bool {
374-
self.to_bytes().eq(&other.to_bytes())
374+
self.to_bytes().eq(other.to_bytes())
375375
}
376376
}
377377
impl Eq for CStr {}

0 commit comments

Comments
 (0)