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
Labels
A-async-await Area: Async & Await A-diagnostics Area: Messages for errors, warnings, and lints A-lifetimes Area: Lifetimes / regions A-trait-system Area: Trait system T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team, which will review and decide on the PR/issue.

Comments

@syntacticsugarglider
Copy link
Contributor

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

@jonas-schievink jonas-schievink added A-async-await Area: Async & Await A-diagnostics Area: Messages for errors, warnings, and lints A-lifetimes Area: Lifetimes / regions A-trait-system Area: Trait system T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team, which will review and decide on the PR/issue. labels Dec 4, 2019
@csmoe
Copy link
Member

csmoe commented Dec 5, 2019

duplicated to #64176

@csmoe csmoe closed this as completed Dec 5, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-async-await Area: Async & Await A-diagnostics Area: Messages for errors, warnings, and lints A-lifetimes Area: Lifetimes / regions A-trait-system Area: Trait system T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

3 participants