negative

Crates.ionegative
lib.rsnegative
version0.1.2
sourcesrc
created_at2024-10-31 14:11:41.935764
updated_at2024-11-08 13:30:19.042212
descriptionNegative impls in stable Rust
homepage
repositoryhttps://github.com/danielhenrymantilla/negative.rs
max_upload_size
id1430131
size30,441
Daniel Henry-Mantilla (danielhenrymantilla)

documentation

https://docs.rs/negative

README

::negative

Negative impls in stable Rust.

Repository Latest version Documentation MSRV unsafe forbidden License CI no_std compatible

Credit to @FlawlessDeveloper for the picture, a modification from a public domain one, see https://discord.com/channels/273534239310479360/1301567644171767890/1302566385968484373


It can be useful to avoid the need to include an ugly PhantomData:

/// Unit struct!
struct SyncButNotSend;

#[::negative::negative_impl]
unsafe impl !Send for SyncButNotSend {}

const _OK: &dyn Sync = &SyncButNotSend;

/// Error, `Send` is not implemented!
const _COMPILE_ERROR: &dyn Send = &SyncButNotSend;

But most importantly, it does change the semantics with regards to coherence (overlapping impls checker), since it makes the trait be explictly unimplemented, becoming a semver promise, rather than the default "this thing happens to be carrying a field type which itself happens not to be implementing said auto-trait yet, so let's make it so the resulting type does not implement saif auto-trait yet either".

struct Foo;

#[::negative::negative_impl]
impl !Unpin for Foo {}

trait Demo {}

impl<T : Unpin> Demo for T {}

impl Demo for Foo {} // <- does not overlap!

Indeed, the following, on the other hand, would fail to compile:

struct Foo(::core::marker::PhantomPinned);

trait Demo {}

impl<T : Unpin> Demo for T {}

impl Demo for Foo {} // <- Error, may overlap!

This is because the way stable Rust traditionally opts out of auto-traits is via lack-of-auto-trait-impl structural infection from Phantom types.

But these types, as far as the coherence checker is concerned, just happen not to be implementing said traits in the current version of the stdlib, that is, they conservatively assume a future, semver-compatible, bump of the standard library may decide to add:

impl Unpin for PhantomPinned {}

Thus, it considers that:

  1. in current Rust, PhantomPinned : Unpin does not hold;

  2. but in some future version of Rust, PhantomPinned : Unpin could hold.

Thus, as far as the coherence checker is concerned, rather than:

PhantomPinned : !Unpin

we actually have:

PhantomPinned : ?Unpin
  • (and so on for all the other auto-traits.)

And thence, Foo : ?Unpin, rather than Foo : !Unpin.

Hence why <T : Unpin> and Foo are conservatively deemed to be able to overlap.

Commit count: 14

cargo fmt