-
Notifications
You must be signed in to change notification settings - Fork 13.1k
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
Error in derived PartialOrd
for structs based on types with incomparable elements.
#49650
Comments
This is very weird because it's inconsistent with the behavior of #[derive(PartialOrd, PartialEq)]
struct MyFloat(f64);
fn main() {
println!("{}", (0.0 / 0.0 >= 0.0) == (MyFloat(0.0 / 0.0) >= MyFloat(0.0)))
} Which is highly inconsistent. This would be a difficult breaking change to make, perhaps not even worth fixing. Edit: I asked on IRC and it seems this issue is somewhat known, but I don't see any other bugs tracking it. |
Why are comparison operators used more than once? This could cause exponential cost, at worst (in the depth of the value), especially for recursive structures. |
We should just forward to This isn't a breaking change, seems like a bug and it doesn't break compilation. |
It's a change of behaviour that people may be relying on. Forwarding to |
I can understand that a fix in such deep integrated code almost automatically involves a breaking change but I would still argue that its actually logically wrong and therefore should be fixed. A potential alternative way could be to add a new lint check which warns about using <= and => on types which only implement (A similar procedure was proposed by @oli-obk in rust-lang/rust-clippy#2626 for a related issue.) |
@0ndorio Oh yeah definitely, I do want to fix this issue and consider the current behaviour a bug too, I'm just pointing out that it is observable and thus people may be relying on it. I'm certainly not hoping that people are relying on it. |
@eddyb: you need both comparison operations per pair of values because there are three conditions ( |
@varkor Can't you use |
Actually, this is going to end up generating a ton of nested |
@varkor What do you mean, can't we rely on the |
Fix derive(PartialOrd) and optimise final field operation ```rust // Before (`lt` on 2-field struct) self.f1 < other.f1 || (!(other.f1 < self.f1) && (self.f2 < other.f2 || (!(other.f2 < self.f2) && (false) )) ) // After self.f1 < other.f1 || (!(other.f1 < self.f1) && self.f2 < other.f2 ) // Before (`le` on 2-field struct) self.f1 < other.f1 || (!(other.f1 < self.f1) && (self.f2 < other.f2 || (!(other.f2 < self.f2) && (true) )) ) // After self.f1 < other.f1 || (self.f1 == other.f1 && self.f2 <= other.f2 ) ``` (The big diff is mainly because of a past faulty rustfmt application that I corrected 😒) Fixes #49650 and fixes #49505.
#49650 (comment) is addressed by #50011. |
Ensure derive(PartialOrd) is no longer accidentally exponential Previously, two comparison operations would be generated for each field, each of which could delegate to another derived PartialOrd. Now we use ordering and optional chaining to ensure each pair of fields is only compared once, addressing #49650 (comment). Closes #49505. r? @Manishearth (sorry for changing it again so soon!) Close #50755
This issue is not totally fixed, only the performance issues were (thanks, @varkor!). Could someone reopen? |
@varkor Ah great, nevermind me then. |
If a type deriving
PartialOrd
wraps another type which contains incomparable elements - and therefore only defines an implementation ofPartialOrd
and not aOrd
- the derived implementations of thele
andge
functions are flawed.The leads to a state where the internal type returns false as result of the expressions
a <= b
andb >= a
for two incomparable elementsa
andb
while the wrapper returns true. [playground]If we look into the attached output of
cargo-expand
it becomes clear that both implementations ignore the the underlying type only implementsPartialOrd
and may contain incomparable elements which can't be checked by(a < b) || !(b < a)
or(a > b) || !(a > b)
.Expanded: Less or Equal
Expanded: Greater or Equal
The text was updated successfully, but these errors were encountered: