Question about async fn in traits: return type is Send or not

⚓ Rust    📅 2025-10-12    👤 surdeus    👁️ 1      

surdeus

//! https://blog.rust-lang.org/2023/12/21/async-fn-rpit-in-traits/

#![allow(dead_code)]

use std::marker::PhantomData;

fn assert_send<T: Send>(_: T) {}

trait Foo {
    // equal to `foo(&self) -> impl Future<..>`
    // not `impl Future<..> + Send`
    async fn foo(&self) {}
}

// A is Send
struct A(u8);

impl Foo for A {}

fn handle_a(a: A) {
    // no err!!!
    // ??? Why a.foo() is Send ???
    assert_send(a.foo());
}

// B is !Send
struct B(PhantomData<*mut u8>);

impl Foo for B {}

fn handle_b(b: B) {
    // err
    // b.foo() is not Send, correct
    assert_send(b.foo());
}

fn handle_foo<F>(f: F)
where
    F: Foo + Send,
{
    // err
    // although F is Send, f.foo() is not Send, correct
    assert_send(f.foo());
}

(Playground)

In handle_b, b.foo() is not Send, in handle_foo, f.foo() is not Send, this is expected. No matter b/f is Send or not, the future is not Send.

But in handle_a, a.foo() is suprisingly Send, this confuses me a lot. Compared A and B, I can assume that a.foo() is Send since A is Send. But f.foo() is not Send even f is Send, so the assumption is definitely wrong.

What is the key point here, what makes a.foo() Send?

2 posts - 2 participants

Read full topic

🏷️ Rust_feed