-
-
Notifications
You must be signed in to change notification settings - Fork 34
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
#![feature(negative_impls)] breaks the guarantee for Unpin provided by pin-project #340
Comments
It seems that a warning that catches this has been implemented.
|
Update: I have discovered today that there is another way to let the coherence checker know that a local type for sure does not implement a trait, which thus triggers this issue as well: ::pin_project_lite::pin_project! {
struct Foo<Pinned, Unpinned> {
#[pin]
pinned: Pinned,
unpinned: Unpinned,
}
}
struct MyPhantomPinned(::core::marker::PhantomPinned);
impl Unpin for MyPhantomPinned
where
for<'cursed> str : Sized,
{}
impl Unpin for Foo<MyPhantomPinned, ()> {}
fn is_unpin<T: Unpin>() {}
fn main() {
is_unpin::<Foo<MyPhantomPinned, ()>>()
} |
@danielhenrymantilla Thanks for finding that trick. I knew that trivial_bounds could be avoided with a lifetime or type parameter (#102 (comment)), but I did not know that it was possible to avoid "conflicting implementations" errors and emulate the complete negative_impls. To be honest, I feel that is a compiler bug of exposing the complete negative_impls to stable. That said, since private-in-public has been implemented (rust-lang/rust#48054), I guess going back to the pre-#53 approach would address a compiler bug. |
To clarify: there is only so much you / a macro can do at this point; we always get back to " I'm afraid reverting #53 won't do the trick, since the mechanism for both is the same (my "negative impl" makes the generated impl, be it post-#53 or pre-#53, be seen as unreachable for the given generic instantiation, and thus, as non-overlapping. However 🤔 there is a "known limitation" of coherence which we could take advantage of, here.
If an associated type defined in a foreign So, if we wrap
impl<'__pin, Pinned, Unpinned>
::pin_project_lite::__private::Unpin
for
Foo<Pinned, Unpinned>
where
<Option< // 👈
__Origin<'__pin, Pinned, Unpinned>
> as IntoIterator>::Item // 👈
: ::pin_project_lite::__private::Unpin,
{} You could even define, in your // Identity type alias.
pub type PinnedFieldsOf<T> = <Option<T> as IntoIterator>::Item; so as to end up with: impl<'__pin, Pinned, Unpinned>
::pin_project_lite::__private::Unpin
for
Foo<Pinned, Unpinned>
where
::pin_project_lite::__private::PinnedFieldsOf< // 👈
__Foo<'__pin, Pinned, Unpinned>
> // 👈
: ::pin_project_lite::__private::Unpin,
{}
|
Ah, I haven't tested but I think you are right.
Thanks. That's an interesting approach...
This is needed to avoid trivial_bounds error. See #102 (comment) for more info. |
pin-project provides an appropriate Unpin implementation by default. Since overlapping implementations are prohibited, this ensures that users cannot add inappropriate Unpin implementations.
However, currently, this guarantee can be broken by using
#[feature(negative_impls)]
: playgroundThanks @danielhenrymantilla for pointing out the interaction with this feature.
The text was updated successfully, but these errors were encountered: