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

Incorrect inference of lifetime bound for existential type #55099

Open
jonhoo opened this Issue Oct 15, 2018 · 3 comments

Comments

Projects
None yet
3 participants
@jonhoo
Copy link
Contributor

jonhoo commented Oct 15, 2018

Consider the following code (playground):

fn reply<'a, I: 'a>(_: I) -> impl Future<Item = (), Error = ()> + 'static {
    // do something with argument
    // then build future that does not borrow I
    futures::future::ok(())
}

fn foo(foo: String) -> Box<Future<Item = String, Error = ()>> {
    Box::new(reply(&foo).map(move |_| foo))
}

This code doesn't compile because impl Trait assumes that all type parameters are in scope for the concrete type. This may get fixed eventually, but for the time being, we can work around it using existential type (rust-lang/rfcs#2071; playground):

#![feature(existential_type)]
existential type Reply: Future<Item = (), Error = ()>;

fn reply<'a, I: 'a>(_: I) -> Reply { futures::future::ok(()) }

fn foo(foo: String) -> Box<Future<Item = String, Error = ()>> {
    Box::new(reply(&foo).map(move |_| foo))
}

However, this pattern does not compose. This example fails to compile (playground):

#![feature(existential_type)]

struct Foo<'a> {
    x: &'a mut (),
}

existential type F1: Future<Item = (), Error = ()>;
existential type F2: Future<Item = (), Error = ()>;

impl<'a> Foo<'a> {
    fn foobar(&mut self) -> F1 {
        futures::future::ok(())
    }

    fn reply<I>(&mut self, _: I) -> F2 {
        self.foobar().and_then(move |_| futures::future::ok(()))
    }
}

with the error

error: non-defining existential type use in defining scope
  --> src/lib.rs:19:40
   |
19 |       fn reply<I>(&mut self, _: I) -> F2 {
   |  ________________________________________^
20 | |         self.foobar().and_then(move |_| futures::future::ok(()))
21 | |     }
   | |_____^ lifetime `'a` is part of concrete type but not used in parameter list of existential type

error: type parameter `I` is part of concrete type but not used in parameter list for existential type
  --> src/lib.rs:19:40
   |
19 |       fn reply<I>(&mut self, _: I) -> F2 {
   |  ________________________________________^
20 | |         self.foobar().and_then(move |_| futures::future::ok(()))
21 | |     }
   | |_____^

I'm not entirely sure why this fails, but it seems like the code should be accepted?

/cc @Nemo157

@jonhoo

This comment has been minimized.

Copy link
Contributor Author

jonhoo commented Oct 15, 2018

Or a somewhat simpler example with just a single existential (playground):

#![feature(existential_type)]

struct Foo<'a> {
    x: &'a mut (),
}

existential type F: Future<Item = (), Error = ()>;

impl<'a> Foo<'a> {
    fn foobar(&mut self) -> Result<(), ()> {
        Ok(())
    }

    fn reply<I>(&mut self, _: I) -> F {
        self.foobar().into_future().and_then(move |_| futures::future::ok(()))
    }
}

jonhoo added a commit to jonhoo/msql-srv that referenced this issue Oct 15, 2018

@jonhoo

This comment has been minimized.

Copy link
Contributor Author

jonhoo commented Nov 14, 2018

@estebank Maybe also tag with A-impl-trait since it's related to existentials? And possibly T-compiler (or is this T-lang terretority?)

jonhoo added a commit to jonhoo/msql-srv that referenced this issue Dec 4, 2018

@Arnavion

This comment has been minimized.

Copy link

Arnavion commented Jan 29, 2019

Smaller repro without futures dependency:

#![feature(existential_type)]

trait Future {
}

struct AndThen<F>(F);

impl<F> Future for AndThen<F> {
}

struct Foo<'a> {
    x: &'a mut (),
}

existential type F: Future;

impl<'a> Foo<'a> {
    fn reply(&mut self) -> F {
        AndThen(|| ())
    }
}

Replacing AndThen(|| ()) with AndThen(()) compiles fine.

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