Skip to content

Higher ranked lifetime error when tryng to see that a future is send. #114046

Open
@antialize

Description

I tried this code:

use std::marker::PhantomData;

trait Callable<'a>: Send + Sync {
    fn callable(data: &'a [u8]);
}

trait Getter<'a>: Send + Sync {
    type ItemSize: Send + Sync;

    fn get(data: &'a [u8]);
}

struct List<'a, A: Getter<'a>> {
    data: &'a [u8],
    item_size: A::ItemSize, // Removing this member causes the code to compile
    phantom: PhantomData<A>,
}

struct GetterImpl<'a, T: Callable<'a> + 'a> {
    p: PhantomData<&'a T>,
}

impl<'a, T: Callable<'a> + 'a> Getter<'a> for GetterImpl<'a, T> {
    type ItemSize = ();

    fn get(data: &'a [u8]) {
        <T>::callable(data);
    }
}

struct ConstructableImpl<'a> {
    _data: &'a [u8],
}

impl<'a> Callable<'a> for ConstructableImpl<'a> {
    fn callable(_: &'a [u8]) {}
}

struct StructWithLifetime<'a> {
    marker: &'a PhantomData<u8>,
}

async fn async_method() {}

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

// This async method ought to be send, but is not
async fn my_send_async_method(_struct_with_lifetime: &mut StructWithLifetime<'_>, data: &Vec<u8>) {
    let _named = List::<'_, GetterImpl<ConstructableImpl<'_>>> {
        data,
        item_size: (),
        phantom: PhantomData,
    };
    assert_send(_named);
    // Moving the await point above the constructed of _named, causes
    // the method to become send, even though _named is Send + Sync
    async_method().await;
}

fn dummy(struct_with_lifetime: &mut StructWithLifetime<'_>, data: &Vec<u8>) {
    assert_send(my_send_async_method(struct_with_lifetime, data));
}

fn main() {}

I expect this code to compile successfully. However the compiler fails to infer that my_send_async_method is SEND, even though it is.

I get the following error message:

$ rustc --version
rustc 1.71.0 (8ede3aae2 2023-07-12)

$ RUST_BACKTRACE=1 cargo build
   Compiling minimal v0.1.0 (/home/jakobt/dev/minimal)
error: implementation of `Getter` is not general enough
  --> src/main.rs:63:5
   |
63 |     assert_send(my_send_async_method(struct_with_lifetime, data));
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Getter` is not general enough
   |
   = note: `Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`...
   = note: ...but `Getter<'2>` is actually implemented for the type `GetterImpl<'2, ConstructableImpl<'_>>`, for some specific lifetime `'2`

error: implementation of `Callable` is not general enough
  --> src/main.rs:63:5
   |
63 |     assert_send(my_send_async_method(struct_with_lifetime, data));
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Callable` is not general enough
   |
   = note: `Callable<'_>` would have to be implemented for the type `ConstructableImpl<'0>`, for any lifetime `'0`...
   = note: ...but `Callable<'1>` is actually implemented for the type `ConstructableImpl<'1>`, for some specific lifetime `'1`

error: higher-ranked lifetime error
  --> src/main.rs:63:5
   |
63 |     assert_send(my_send_async_method(struct_with_lifetime, data));
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: could not prove `impl Future<Output = ()>: Sync`

error: could not compile `minimal` (bin "minimal") due to 3 previous errors

This does not make sense, GetterImpl (and ConstructableImpl) cannot possible be constructed with two different lifetimes since that goes against the definition.

If we remove the call to async_method().await The assert_send(_named) show that _named is indeed Send and Sync, so the method should also me.

I have minimized this example as much as I can, removing any of the current parts resolves the issue. Removing the lifetime on StructWithLifetime, does not resolve the issue but changes the error message to

error: higher-ranked lifetime error
  --> src/main.rs:61:5
   |
61 |     assert_send(my_send_async_method(struct_with_lifetime, data));
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: could not prove `impl Future<Output = ()>: Send`

error: higher-ranked lifetime error
  --> src/main.rs:61:5
   |
61 |     assert_send(my_send_async_method(struct_with_lifetime, data));
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: could not prove `impl Future<Output = ()>: Sync`

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Labels

    A-async-awaitArea: Async & AwaitA-higher-rankedArea: Higher-ranked things (e.g., lifetimes, types, trait bounds aka HRTBs)AsyncAwait-TriagedAsync-await issues that have been triaged during a working group meeting.C-bugCategory: This is a bug.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.T-typesRelevant to the types team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions