Skip to content

Short-circuit Rc/Arc equality checking on equal pointers where T: Eq #56550

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

Merged
merged 3 commits into from
Dec 19, 2018

Conversation

chpio
Copy link
Contributor

@chpio chpio commented Dec 5, 2018

based on #42965

Is the use of the private trait ok this way? Is there anything else needed for this to get pulled?

@rust-highfive
Copy link
Contributor

Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @Mark-Simulacrum (or someone else) soon.

If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes.

Please see the contribution instructions for more information.

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Dec 5, 2018
@Mark-Simulacrum
Copy link
Member

r? @alexcrichton

Copy link
Contributor

@oli-obk oli-obk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have tests anywhere along the lines of

    let x = std::rc::Rc::new(std::f32::NAN);
    assert_ne!(x, x);

@oli-obk oli-obk added the T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. label Dec 6, 2018
@chpio
Copy link
Contributor Author

chpio commented Dec 8, 2018

@oli-obk added a few tests, but it think they are somewhat wanky, testing the specific impl.

@alexcrichton
Copy link
Member

Thanks for the PR @chpio and sorry for the delay! Initially reading this I was wary that this would break cases like @oli-obk mentioned above, but I think after reading over it this is correct and we should consider merging it.

@rfcbot fcp merge

For those just joining, this reimplements PartialEq for Rc<T> and Arc<T> with internal specialization that does a pointer check before calling T::eq if T: Eq. According to Eq's own documentation it signifies the reflexive property (a == a) which I believe means that this is a semantically correct implementation.

One minor worry I'd have is that for very simple T this may cause Rc<T>::eq to be a bit slower. For example Rc<i32> may be more expensive now as the previous one tiny branch is now two tiny branches. Have others seen this sort of optimization in standard libraries before? Should we be wary of something like this?

@rfcbot
Copy link
Collaborator

rfcbot commented Dec 11, 2018

Team member @alexcrichton has proposed to merge this. The next step is review by the rest of the tagged teams:

No concerns currently listed.

Once a majority of reviewers approve (and none object), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up!

See this document for info about what commands tagged team members can give me.

@rfcbot rfcbot added proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. labels Dec 11, 2018
@withoutboats
Copy link
Contributor

We document that Eq is supposed to be reflexive, but unsafe code cannot rely on that, so its plausible that some implementations aren't following that. Isn't it possible this will break someone's code in which they had a non-reflexive PartialEq that still impl'd Eq? Are we fine with that?

@SimonSapin
Copy link
Contributor

Code would only break if it relies on a buggy implementation of Eq to stay buggy. I have a hard time to think of a "real" case where that could happen.

@alexcrichton
Copy link
Member

Another good point to bring up @withoutboats! In addition to relying on a buggy Eq implementation they'd also have to be relying somehow on PartialEq for Rc<BuggyType>, which I think puts me in @SimonSapin's camp of "seems very unlikely to come up in practice"

@withoutboats
Copy link
Contributor

I think I'm inclined to agree, mainly from a pragmatic perspective - its not likely to come up in practice. But I'm uncertain what our general guidelines around backwards compatibility in regard to the "guarantees" that are made about the behavior of traits in std. There's nothing unsafe about making an Eq impl that isn't reflexive, and you can't rely on that reflexivity to uphold memory invariants. So where is the line drawn on whose backwards compatibility we are willing to guarantee? Which unenforced contracts of traits are considered "bugs" not to uphold?

For example, members of the team have previously argued that types that implement both ToString and FromStr should be roundtrippable, would we consider a third party library that doesn't uphold that guarantee similarly buggy and be fine if a change to std broke them? That's what I'm trying to clarify, I guess: we can't actually rely on ecosystem impls upholding untyped contracts, how much allowance is there to implement the traits in a manner different from their documented intent?

@SimonSapin
Copy link
Contributor

There's nothing unsafe about making an Eq impl that isn't reflexive,

But there’s nothing unsafe about changing the result of Rc<Foo>::eq either, is there?

@withoutboats
Copy link
Contributor

@SimonSapin Definitely not. This is about backwards compatibility.

I bring up unsafe because if the contract were reliable for to avoid UB, breaking that code would clearly be permissible. If Eq were an unsafe trait and we could rely on its reflexivity for memory safety, clearly it would be permissible to break code with a non-reflexive Eq impl, because it failed to uphold the invariants its required to as unsafe code.

But the reflexivity is in this different category of contracts, which only exist in the std documentation and aren't part of the language. How do we draw the line about which of those contracts you need to uphold to get backwards compatibility from std, and which are just contracts that std is guaranteeing to uphold?

@alexcrichton
Copy link
Member

I think the way I typically approach these kinds of problems is that we strive toward the world we want to be in, for example where Eq always represents reflexivity. If, however, along the way we do something that ends up having a large practical impact because that's in fact not true (aka not everything is reflexive) then we backpedal and figure out how to work with that.

That may be a bit cavalier though and certainly isn't as conservative as we could be. In any case one thing I've forgotten is that we could certainly run a crater run for this and just see if there's any impact there initially.

@bors: try

@bors
Copy link
Collaborator

bors commented Dec 12, 2018

⌛ Trying commit d828c22 with merge aa49d8ef14939ddec0e34b346b60174a5673d48f...

@bors
Copy link
Collaborator

bors commented Dec 12, 2018

☀️ Test successful - status-travis
State: approved= try=True

@alexcrichton
Copy link
Member

@craterbot run start=master#bd47d6825bf4090517549d33cfef10d3300b4a75 end=try#aa49d8ef14939ddec0e34b346b60174a5673d48f mode=build-and-test

@Kimundi
Copy link
Member

Kimundi commented Dec 12, 2018

I see it similar to the ability to define a Clone impl for a T: Copy that does more than just a memcpy: Its safe to do so, but a violation of the interface, so if some code does not end up calling the method its because you misused the interface.

@rfcbot rfcbot added final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. and removed proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. labels Dec 12, 2018
@rfcbot
Copy link
Collaborator

rfcbot commented Dec 12, 2018

🔔 This is now entering its final comment period, as per the review above. 🔔

@chpio
Copy link
Contributor Author

chpio commented Dec 13, 2018

Is crater just calling cargo check? It would be pretty useless for this PR if that's the case.

@memoryruins
Copy link
Contributor

The current agent is in build-and-test mode (check the final portion of the command issued to craterbot).

@craterbot
Copy link
Collaborator

🎉 Experiment pr-56550 is completed!
📊 13 regressed and 14 fixed (50551 total)
📰 Open the full report.

⚠️ If you notice any spurious failure please add them to the blacklist!
ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@craterbot craterbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-crater Status: Waiting on a crater run to be completed. labels Dec 16, 2018
@chpio
Copy link
Contributor Author

chpio commented Dec 16, 2018

couldn't spot any meaningful regressions here, just some timing or env-var not set failures. is anyone else willing to look into it?

@alexcrichton
Copy link
Member

I took a look myself and some of them looked suspicious but they were all spurious I think. Many of the failures do indeed use Arc and Rc internally, but they didn't seem to be failing due to this PR. In that case this looks good to go, thanks again @chpio!

@bors: r+

@bors
Copy link
Collaborator

bors commented Dec 17, 2018

📌 Commit d828c22 has been approved by alexcrichton

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Dec 17, 2018
@bors
Copy link
Collaborator

bors commented Dec 19, 2018

⌛ Testing commit d828c22 with merge 74ebf02...

bors added a commit that referenced this pull request Dec 19, 2018
Short-circuit Rc/Arc equality checking on equal pointers where T: Eq

based on #42965

Is the use of the private trait ok this way? Is there anything else needed for this to get pulled?
@RalfJung
Copy link
Member

Wouldn't it make sense to also do the same when comparing &[mut] T? That seems to be the far more obvious case than Rc/Arc.

And then comparison of Rc/Arc could be implemented via deref.

@chpio
Copy link
Contributor Author

chpio commented Dec 19, 2018

@RalfJung #42965 (comment)

@RalfJung
Copy link
Member

@chpio Ah that's why I didn't find it, it's in a different PR.

I think such conclusions should be added as comments in the source code, they'll be lost otherwise.

@bors
Copy link
Collaborator

bors commented Dec 19, 2018

☀️ Test successful - status-appveyor, status-travis
Approved by: alexcrichton
Pushing 74ebf02 to master...

@bors bors merged commit d828c22 into rust-lang:master Dec 19, 2018
@chpio chpio deleted the rc-eq branch December 19, 2018 12:57
@chpio
Copy link
Contributor Author

chpio commented Dec 19, 2018

I think such conclusions should be added as comments in the source code, they'll be lost otherwise.

hmm, yeah. are you saying i should make a new pr for that?

@RalfJung
Copy link
Member

That would be great :)

@rfcbot rfcbot added finished-final-comment-period The final comment period is finished for this PR / Issue. and removed final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. labels Dec 22, 2018
Centril added a commit to Centril/rust that referenced this pull request May 11, 2019
add comment to `Rc`/`Arc`'s `Eq` specialization

in addition to rust-lang#56550

rust-lang#42965 (comment)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. finished-final-comment-period The final comment period is finished for this PR / Issue. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.