-
Notifications
You must be signed in to change notification settings - Fork 13.3k
[r+] Add rules for negative implementations #20972
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
Conversation
r? @pcwalton (rust_highfive has picked a reviewer for you, use r? to override) |
(running stage2 checks locally, stage1 rpass/cfail passed) UPDATE:passed :) |
impl<T> !marker::Send for Rc<T> {} | ||
|
||
#[cfg(not(stage0))] // NOTE remove cfg after next snapshot | ||
impl<T> !marker::Sync for Rc<T> {} |
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.
Isn't this redundant with raw pointers no longer being Send?
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.
It's redundant unless, for some reason, NonZero
ends up implementing Send
. It doesn't now and I don't think it will so we could probably remove it. Although, the extra negative impl is harmless.
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 think it's good practice though to be explicit; it serves as documentation. It'd be good to add some comments to the impls though saying why Rc
is not sendable/sync. something like
/// `Rc` instances cannot be sent to other threads because they contain a shared reference count which is modified without atomic instructions.
impl<T> !marker::Send for Rc<T> { }
/// `Rc` instances cannot be sent to other threads because they contain a shared reference count which is modified without atomic instructions.
impl<T> !marker::Sync for Rc<T> { }
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.
An alternative, if we had such a thing, would be the equivalent of compile-fail unit tests though.
dad2440
to
7fde099
Compare
if let Some(neg_impls) = self.tcx.trait_negative_impls.borrow().get(&k) { | ||
impls.push_all(neg_impls.borrow().as_slice()); | ||
} | ||
(k, impls) |
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.
This seems a bit fishy. If there are only negative impls, it seems like the result will be the empty vec, but I think we just want the pos + the neg impls.
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.
If there are no positive impls - trait_impls
is empty - the result would be an empty vec, yes. Although, trait_impls
will never be empty, afaict.
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.
(by merging trait_impls
and trait_negative_impls
this won't be needed anymore)
So overall this looks really good. I'm happy about how small the diff became when we adopted the "unify pos and neg impl" approach. I feel like there should be more tests, but I'm not entirely sure what they ought to be. Maybe we can brainstorm some tricky scenarios. Here are some thoughts:
struct Foo;
struct Bar(Foo);
impl !Send for Foo;
fn is_send<T:Send>();
fn main() {
is_send::<Bar>(); //~ ERROR ...
is_send::<(int, Foo)>(); //~ ERROR ...
is_send::<Box<Foo>>(); //~ ERROR ...
is_send::<Box<Bar>>(); //~ ERROR ...
} I put the one minor nit about keeping the pos/neg impls in one list instead of two -- do you think there is a good reason to keep them separated? |
@nikomatsakis thanks for the review :) I believe |
6fd3e62
to
d8b507c
Compare
d8b507c
to
d87b71d
Compare
r+ |
…tsakis This PR adds rules for negative implementations. It follows pretty much what the [RFC](https://github.com/rust-lang/rfcs/blob/master/text/0019-opt-in-builtin-traits.md) says with 1 main difference: Positive implementations don't override negative implementations @nikomatsakis r? cc #13231 [breaking-change]
Why don't positive implementations override negative implementations? I think this is pretty important for some uses of unsafe traits, no? |
8544522
to
7cd762a
Compare
@pythonesque I've updated the PR description with something that reflects the current implementation. The previous message corresponded to an older version of this implementation. |
…tsakis This PR adds rules for negative implementations. It follows pretty much what the [RFC](https://github.com/rust-lang/rfcs/blob/master/text/0019-opt-in-builtin-traits.md) says with 1 main difference: Instead of positive implementations override negative implementations, this have been implemented in a way that a negative implementation of `Trait` for `T` will overlap with a positive implementation, causing a coherence error. @nikomatsakis r? cc #13231 [breaking-change]
On Thu, Jan 15, 2015 at 08:45:23PM -0800, Joshua Yanovski wrote:
It wasn't clear where this would be important. Do you have a use case? |
@nikomatsakis Maybe you are right and it doesn't, I think I had an example in mind but I can't remember what it was at the moment. I'll let you know if I remember. |
@nikomatsakis there are some patterns involving type-level search that can't currently be expressed in Rust as far as I can tell, but might be possible with blanket negative impls allowing positive impl overrides (sealed traits with overlapping patterns would be another way). One use case for that is generic programming with open sums (like the join type proposal). Another one would be statically checked dimensional analysis. Fancy database interfaces could also use that pattern for a number of things. |
On Sun, Jan 18, 2015 at 10:38:12AM -0800, Darin Morrison wrote:
Interesting, I'd like to hear more details. Nonetheless, it feels good |
@nikomatsakis If I get a chance I'll try to put together some examples. Most of the ones I can think of at the moment can be encoded as a special case of a decidable equality on types by piggybacking on the definitional equality. Once equality predicates in where clauses are implemented, that might actually be enough, assuming they can be negated and that the coherence check could use that to determine disjointness of the implementations. |
@darinmorrison please, keep me in the loop and thanks for bringing this up! 👍 |
This PR adds rules for negative implementations. It follows pretty much what the RFC says with 1 main difference:
Instead of positive implementations override negative implementations, this have been implemented in a way that a negative implementation of
Trait
forT
will overlap with a positive implementation, causing a coherence error.@nikomatsakis r?
cc #13231
[breaking-change]