1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#![no_std]

//! This crate provides [`SendFuture::send`] workaround for compiler bug
//! [https://github.com/rust-lang/rust/issues/96865](https://github.com/rust-lang/rust/issues/96865)
//!
//! See documentation of [`SendFuture`] trait for example usage

/// This trait is used as a workaround for compiler bug
/// [https://github.com/rust-lang/rust/issues/96865](https://github.com/rust-lang/rust/issues/96865)
///
/// Compilation of code calling async methods defined using `impl` syntax within [`Send`] async functions
/// may fail with hard-to-debug errors.
///
/// The following fails to compile with rustc 1.78.0:
///
/// ```compile_fail
/// trait X {
///     fn test<Y>(&self, x: impl AsRef<[Y]>) -> impl core::future::Future<Output = ()> + Send
///     where
///         Y: AsRef<str>;
/// }

/// fn call_test(x: impl X + Send + Sync) -> impl core::future::Future<Output = ()> + Send {
///     async move { x.test(["test"]).await }
/// }
/// ```
///
/// ```text
/// error: implementation of `AsRef` is not general enough
///   --> src/lib.rs:66:9
///    |
/// 66 |         async move { x.test(["test"]).await }
///    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `AsRef` is not general enough
///    |
///    = note: `[&'0 str; 1]` must implement `AsRef<[&'1 str]>`, for any two lifetimes `'0` and `'1`...
///    = note: ...but it actually implements `AsRef<[&str]>`
/// ```
///
/// The fix is to call [`send`](SendFuture::send) provided by this trait on the future before awaiting:
/// ```
/// use send_future::SendFuture as _;
///
/// trait X {
///     fn test<Y>(&self, x: impl AsRef<[Y]>) -> impl core::future::Future<Output = ()> + Send
///     where
///         Y: AsRef<str>;
/// }

/// fn call_test(x: impl X + Send + Sync) -> impl core::future::Future<Output = ()> + Send {
///     async move { x.test(["test"]).send().await }
/// }
/// ```
pub trait SendFuture: core::future::Future {
    fn send(self) -> impl core::future::Future<Output = Self::Output> + Send
    where
        Self: Sized + Send,
    {
        self
    }
}

impl<T: core::future::Future> SendFuture for T {}

#[allow(unused)]
#[cfg(test)]
mod tests {
    use super::SendFuture as _;

    trait X {
        fn test<Y>(&self, x: impl AsRef<[Y]>) -> impl core::future::Future<Output = ()> + Send
        where
            Y: AsRef<str>;
    }

    fn call_test(x: impl X + Send + Sync) -> impl core::future::Future<Output = ()> + Send {
        async move { x.test(["test"]).send().await }
    }
}