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

`impl Trait` Associated Types Do Not Leak Auto Traits #49288

Open
cramertj opened this Issue Mar 22, 2018 · 2 comments

Comments

Projects
None yet
3 participants
@cramertj
Copy link
Member

cramertj commented Mar 22, 2018

While auto trait impls of impl Trait types leak, the auto trait impls of their associated types do not:

#![feature(conservative_impl_trait)]

trait Foo {
    type Bar;
}

fn require_bar_send<F>(_: F) where F: Foo, F::Bar: Send {}

fn foo() -> impl Foo {
    struct Fooey;
    impl Foo for Fooey {
        type Bar = ();
    }
    Fooey
}

fn main() {
    require_bar_send(foo()); // ERROR
}

This can be fixed by writing impl Foo<Bar=impl Send>, but this can get annoying quickly: async traits, whose methods each return a separate associated type implementing Future, need to have a Bar=impl Send for each method:

trait Foo {
    type FooFut: Future<...>;
    fn foo(&self) -> Self::FooFut;

    type BarFut: Future<...>;
    fn bar(&self) -> Self::BarFut;

    type BazFut: Future<...>;
    fn baz(&self) -> Self::BazFut;
}

fn foo() -> impl Foo<FooFut=impl Send, BarFut=impl Send, BazFut=impl Send> { ... }

This isn't a bug, but I'm interested in seeing if there're ways we can improve here-- should associated type auto traits leak? I can see that becoming a huge problem since you'd then want the associated types of associated types auto traits to leak, etc, but there's not an obvious solution to me. I really just want an "everything you care about here is thread-safe" button, but I don't know how to supply that easily.

@cramertj

This comment has been minimized.

Copy link
Member Author

cramertj commented Mar 22, 2018

Probably the right solution for my particular case is first-class async fn in traits, where the future returned from async fn foo(&self) is guaranteed to be Send so long as Self: Send. cc @withoutboats

@Centril Centril added the T-lang label Mar 22, 2018

@Centril

This comment has been minimized.

Copy link
Contributor

Centril commented Mar 23, 2018

Assuming the following is legal:

trait SendFoo = Foo<FooFut = impl Send, BarFut = impl Send, BazFut = impl Send>;

fn foo() -> impl SendFoo { ... }

it does seem like an ergonomic effect to do write things.

If we gain ConstraintKinds or "trait-parametric polymorphism", then you could also write:

trait ExtraFoo<trait X> = Foo<FooFut = impl X, BarFut = impl X, BazFut = impl X>;

fn foo() -> impl ExtraFoo<Send> { ... }

which is general and polymorphic over any extra trait you like.

Instead of leaking auto traits in assoc types, I'd like to go the other direction and not leak auto traits anywhere.

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