Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unexpected interactions with async blocks, auto traits, and trait objects #67036

Closed
syntacticsugarglider opened this issue Dec 4, 2019 · 1 comment

Comments

@syntacticsugarglider
Copy link

@syntacticsugarglider syntacticsugarglider commented Dec 4, 2019

The source below does not compile, where the expected behavior is for it to compile as far as I can tell. Removing the Send bound on drop_send causes it to compile. Removing the async {}.await no-op causes it to compile. This seems likely related to #64552, with the same sort of leakage of regions that should not be user-visible occurring. However, the error message is quite opaque in this case.

note: `Bound` would have to be implemented for the type `(dyn Object + '0)`, for any lifetime `'0`...
   = note: ...but `Bound` is actually implemented for the type `(dyn Object + '1)`, for some specific lifetime `'1`

My presumption is therefore that the auto trait is being correctly satisfied in the generator for some lifetime, the implementation of Bound is implicitly constrained on Send by Object where the async block is required to be Send, so #64552 is occurring in a lifetime-dependent fashion resulting in an altogether surprising error message. I'm not as familiar with borrow checker internals as I'd like so this may be barking up the wrong tree.

I am, however, unclear as to why the associated type parametrization over T::Type as opposed to simply T is necessary to reproduce.

use std::marker::PhantomData;

// remove this Send bound and it compiles
fn drop_send<F: Send>(_: F) {}

trait Object: Send {}

pub trait Bound {
    type Type;
}

impl Bound for dyn Object {
    type Type = ();
}

trait Contains<T> {}

struct IsBound<T: Bound + ?Sized>(PhantomData<dyn Contains<T::Type> + Send>);

impl<T: Bound + ?Sized> IsBound<T> {
    pub fn new() -> Self {
        IsBound(PhantomData)
    }
}

fn fails() {
    drop_send(async {
        let collection: IsBound<dyn Object> = IsBound::new();

        // comment out this no-op and it builds:
        async {}.await;
    })
}

Finally, here is a playground demonstrating this issue to show independence from any local state of my own system

@csmoe

This comment has been minimized.

Copy link
Member

@csmoe csmoe commented Dec 5, 2019

duplicated to #64176

@csmoe csmoe closed this Dec 5, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants
You can’t perform that action at this time.