-
Notifications
You must be signed in to change notification settings - Fork 13k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Tweaks to equality comparisons for slices/arrays/vectors #22320
Conversation
0 1 2 3 4 5 6 7 8 9 | ||
10 11 12 13 14 15 16 17 18 19 | ||
20 21 22 23 24 25 26 27 28 29 | ||
30 31 32 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a little worried about the impact this has on the metadata, this seems like a huge number of implementations being thrown in, not all of which are really that necessary. Can you make sure we're not blowing up the metadata by a few megabytes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just by comparing the sizes of produced rlibs before and after or is there a smarter way to compare rlibs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@alexcrichton
Sadly, the bloat is significant.
libcore: 36MB -> 39MB
libcollections: 11MB -> 18MB (15MB without CowVec
impls)
Besides, if I purge libcore/array.rs completely, then libcore.rlib loses another 6MB and becomes 30MB.
That's one more reason, why we need something like this sooner.
I think the reasonable subsequent actions would be:
- Keep the macros
- Keep the "status quo" impls
- Add the impls crucial for Byte string literals should have a type of a fixed size #18465
Then the bloat should be tolerable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm yeah this is quite unfortunate how big a blowup this is (11MB => 18MB is huge!). I suspect there is a huge trove of optimizations that we could exploit for metadata layout, but unfortunately it will take time to examine.
I think that your proposed sequence of actions should be fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(thanks for analyzing by the way!)
Also, for the future, I analyze metadata by running ar x libfoo.rlib
and then looking at rust.metadata.bin
to see how big it is.
I feel like a bit of explicitness when using a |
The status quo is " |
cc @japaric |
@petrochenkov Have you tried using a As a first attempt this compiles: #![crate_type = "lib"]
trait AsSlice {
type Elem;
fn as_slice(&self) -> &[Self::Elem];
}
trait PartialEq<T: ?Sized = Self> {
fn eq(&self, &T) -> bool;
}
impl<T: AsSlice, U: AsSlice> PartialEq<T> for U where
T::Elem: PartialEq<U::Elem>,
{
fn eq(&self, _: &T) -> bool {
true
}
} But I don't know if that may have more problem down the line because of conflicts with other |
@japaric |
@petrochenkov yeah, seems like because of those reference impls this approach will require negative bounds at some point. Hmm, I wonder how bad it would be remove those Yet another idea to reduce the impl bloat, is to make the |
@japaric I don't know how feasible that is. That sort of magic is definitely tricky to get right and tends to produce edge cases of its own. It might work out. |
@japaric |
I don't like this idea for two reasons:
|
Rebased and updated with reduced code bloat. Some tests use fixed-size arrays in weird ways, if they are adjusted, then 2 x 2 x 32 more impls of |
⌛ Testing commit 5e616db with merge de81c9a... |
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
💔 Test failed - auto-linux-64-x-android-t |
@bors: retry |
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
, 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]>
andArc<[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