Skip to content

Enforce no (stable) auto traits are implemented for the returned Future #1

Open
@ghost

Description

Currently #[clear] (and maybe also #[set]) do not enforce that as this compiles:

#[async_auto_traits::clear]
async fn foo() {}

fn assert_send(_: impl Send) {}

fn main() {
    assert_send(foo());
}

Because impl Future does not hide auto traits.

The enforcement could be done through something like this (play):

use pin_project_lite::pin_project;
use std::{
    future::Future,
    marker::PhantomData,
    pin::Pin,
    task::{Context, Poll},
};

pin_project! {
    pub struct NotSendButSyncFuture<F: Future> {
        #[pin]
        future: F,
        ghost: PhantomData<*const ()>,
    }
}

unsafe impl<F: Future + Sync> Sync for NotSendButSyncFuture<F> {}

impl<F: Future> NotSendButSyncFuture<F> {
    pub fn new(future: F) -> Self {
        Self {
            future,
            ghost: PhantomData,
        }
    }
}

impl<F: Future> Future for NotSendButSyncFuture<F> {
    type Output = F::Output;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        self.project().future.poll(cx)
    }
}

fn foo() -> impl Future {
    NotSendButSyncFuture::new(async move { todo!() })
}

fn assert_send(_: impl Send) {}

fn main() {
    assert_send(foo());
}

Or something like this (but may not work properly for async fns that have no .await, play):

use std::{future, marker::PhantomData};

async fn foo() {
    let _phantom = PhantomData::<*mut ()>;
    future::ready(()).await;
}

fn assert_send_sync(_: impl Send + Sync) {}

fn main() {
    assert_send_sync(foo());
}

(Moved from rust-lang/rust#82187 (comment), sorry for being off-topic there!)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions