Search code examples
rustfuture

A bit confusing compiler error message around Boxed Future in Rust


I don't seem to understand the compiler error message here. For the following snippet

use std::pin::Pin;
use std::future::Future;

fn give_future<'a>(x : &'a i32) -> Pin<impl Future<Output=&'a i32> + 'a> {
    Box::pin(async move { x })
}

it says the following

error[E0277]: `[async block@src/lib.rs]` cannot be unpinned
 --> src/lib.rs:7:47
  |
  | fn give_future<'a>(x : &'a i32) -> Pin<impl Future<Output=&'a i32> + 'a> {
  |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Unpin` is not implemented for `[async block@src/lib.rs]`
  |
  = note: consider using the `pin!` macro
          consider using `Box::pin` if you need to access the pinned value outside of the current scope
  = note: required for `Box<[async block@src/lib.rs]>` to implement `Future`

For more information about this error, try `rustc --explain E0277`.

From what I understand, Pinx<Box<impl Future>> is being returned as Pin<impl Future>. Why isn't the compiler just saying that?


Solution

  • From what I understand, Pin<Box<impl Future>> is being returned as Pin<impl Future>. Why isn't the compiler just saying that?

    The basis for what you've written could be a perfectly viable thing to do. Probably not with Pin in particular (since it is quite narrow and nuanced in its functionality) but masquerading Box<T> as impl Trait is a thing that is done all the time to avoid leaking internal details and can work because traits are commonly implemented on Box<T>s where T: Trait.

    So the compiler is simply trying to satisfy your request. To do so it only needs to verify that Box<T> implements Future, and it has an implementation but only if that T implements Unpin. And thus you get the error.