-
Notifications
You must be signed in to change notification settings - Fork 13.8k
clippy fix: remove manual PartialEq::ne #143377
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
base: master
Are you sure you want to change the base?
Conversation
Note that implementations for reference types are not strictly the same as the default because they are forwarding of the underlying implementation. In such cases, if the compiler cannot optimize the inversion of the result from the underlying implementation (e.g., inline assembly or FFI is used), then |
@taiki-e that is a good point, thanks! |
fe36c54
to
eac6335
Compare
This comment has been minimized.
This comment has been minimized.
eac6335
to
4489647
Compare
library/core/src/cmp.rs
Outdated
// if <A as PartialEq<B>>::ne uses inline assembly or FFI, then | ||
// this forwarding impl may be more efficient than the default impl | ||
#[allow(clippy::partialeq_ne_impl)] |
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.
Probably allow
->expect
so we get a bit of noise if these change for some reason.
Maybe just make this a module-level attribute? Since it applies to all but one fn ne
in this file.
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.
But at module level would it not also conflict with the few missing ne, at least as expect
?
I was thinking of removing duplication a bit with a macro here, since the four cases of (&mut, &mut)
, (&mut, &)
, (&, &mut)
, (&, &)
are (nearly?) identical. That would also collapse most of these annotations...
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've now collapsed this with macros to just one PartialEq::ne
impl with an expect.
4489647
to
88f2556
Compare
I don't think we should add macros to appease the thing that is linting in an effort to make the code more readable. Adding macros is rather the opposite of making the code more readable. |
@workingjubilee macros like these are used all over the library for repeating impls just like here... Do you feel the same way about those, or can you explain why you think these are any different? |
If you look you will find that I have pushed people to reduce the usage of macros in other PRs, yes. |
Very well, I was just trying to clarify your point. Macros come with the disadvantage of more complicated code, but one advantage of using macros like this is that it is easier to see which code is identically duplicated and which parts contain differences. Opinions will vary on in which cases the upside outweighs the downside. My latest change introduced 3 macros:
|
I don't have any strong preferences here r? workingjubilee |
|
59bece7
to
3c1c6e9
Compare
☔ The latest upstream changes (presumably #143867) made this pull request unmergeable. Please resolve the merge conflicts. |
3c1c6e9
to
9c60f35
Compare
#[inline] | ||
fn ne(&self, other: &Self) -> bool { *self != *other } |
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.
Primitive ne
isn't equivalent to !(*self == *other)
. This difference goes straight to MIR and codegen:
rust/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
Lines 822 to 833 in 0fb279b
mir::BinOp::Ne | |
| mir::BinOp::Lt | |
| mir::BinOp::Gt | |
| mir::BinOp::Eq | |
| mir::BinOp::Le | |
| mir::BinOp::Ge => { | |
if is_float { | |
bx.fcmp(base::bin_op_to_fcmp_predicate(op), lhs, rhs) | |
} else { | |
bx.icmp(base::bin_op_to_icmp_predicate(op, is_signed), lhs, rhs) | |
} | |
} |
Yes it can be trivially optimized away but why emit additional IR when you can emit less?
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.
Interesting! I suppose that treatment may be necessary in case these are implemented by inline assembly or via FFI.
Yes it can be trivially optimized away but why emit additional IR when you can emit less?
The documentation in this very file says that:
/// The default implementation of `ne` provides this consistency and is almost
/// always sufficient. It should not be overridden without very good reason.
Is the performance impact of emitting slightly more IR really a very good reason? I would expect it is on the edge of immeasurable.
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.
Is the performance impact of emitting slightly more IR really a very good reason? I would expect it is on the edge of immeasurable.
That is a very interesting question since we do in fact have some measurements! Let's at least find out if our existing ones would say anything.
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.
My reservation wasn't mainly about the performance impact. I'm thinking of alternative codegen backends that read Rust MIR and generate code with instruction sets that have ne as well as eq for primitives.
Rather than telling people to rely on MIR opts or LLVM opts (when the backend may not be LLVM) I'd prefer us to do something better on the outset.
The other thing is that it just feels weird? I just don't think clippy is very applicable to this specific case.
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.
And like, what's the benefit here? Of course we don't have to be biased towards the status quo but what is the difference between the change and the status quo?
These are just two lines in a macro. Removing them isn't too much different from keeping them.
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.
The difference would be that the code would then do what the comment about implementing ne
seems to recommend. Removing ne
is just one of three ways of achieving that, and merely the one that seemed most likely to work at the time. But I'm also happy to document the "very good reason" why we want to impl ne
here, or change the comment or both.
☔ The latest upstream changes (presumably #144997) made this pull request unmergeable. Please resolve the merge conflicts. |
9c60f35
to
187c020
Compare
This comment has been minimized.
This comment has been minimized.
The question of measurable performance impact if any was raised so we might as well test this much, even if it's not the be-all end-all of performance testing since our runtime benches remain lacking: @bors try @rust-timer queue |
This comment has been minimized.
This comment has been minimized.
clippy fix: remove manual PartialEq::ne
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Finished benchmarking commit (ed44707): comparison URL. Overall result: no relevant changes - no action neededBenchmarking this pull request means it may be perf-sensitive – we'll automatically label it not fit for rolling up. You can override this, but we strongly advise not to, due to possible changes in compiler perf. @bors rollup=never Instruction countThis benchmark run did not return any relevant results for this metric. Max RSS (memory usage)Results (primary 2.8%, secondary 0.4%)A less reliable metric. May be of interest, but not used to determine the overall result above.
CyclesResults (secondary -2.2%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Binary sizeResults (primary -0.0%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Bootstrap: 469.26s -> 468.084s (-0.25%) |
☔ The latest upstream changes (presumably #144847) made this pull request unmergeable. Please resolve the merge conflicts. |
library/core/src/cmp.rs
Outdated
PartialEq::ne(*self, *other) | ||
} | ||
} | ||
partial_ord_impl!((&A => A, &B => B) /*(&A => A, &mut B => B) (&mut A => A, &B => B)*/ (&mut A => A, &mut B => B)); |
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.
My primary objection with macros is I find deducing their invented syntax, like this, to often be confounding, unless it is a simple listing of things. I broadly prefer it when the "argument" continues to look like Rust code, and am actually willing to tolerate a more complex macro if it continues looking like Rust code. It also is nice if a span actually consistently points to the trait definition instead of a macro invocation.
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.
The following oversimplified example is valid to do:
trait Something {
fn stuff();
fn thingy();
}
macro_rules! something_body {
() => {
fn stuff() {
()
}
fn thingy() {
()
}
}
}
impl Something for u8 {
something_body!();
}
I would somewhat prefer it.
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 these comments. I agree that the current invented syntax is not optimal. I'll see if I can do better.
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 changed the syntax to be more rust-like. Let me know if it helps.
@rustbot ready
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 just happened across https://github.com/rust-lang/rust/blob/master/library/std/src/path.rs#L3594-L3685 which does things very similarly to my current proposal.
@rustbot author |
187c020
to
a31104c
Compare
This PR was rebased onto a different master commit. Here's a range-diff highlighting what actually changed. Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers. |
Removes manual impls of PartialEq::ne which are equivalent to the default.