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

Incorrect inference of lifetime bound for existential type #55099

Closed
jonhoo opened this issue Oct 15, 2018 · 3 comments · Fixed by #70131
Closed

Incorrect inference of lifetime bound for existential type #55099

jonhoo opened this issue Oct 15, 2018 · 3 comments · Fixed by #70131
Labels
A-impl-trait Area: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch. A-lifetimes Area: Lifetimes / regions F-type_alias_impl_trait `#[feature(type_alias_impl_trait)]` requires-nightly This issue requires a nightly compiler in some way.

Comments

@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
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
@estebank estebank added the A-lifetimes Area: Lifetimes / regions label Oct 16, 2018
@jonhoo
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?)

@estebank estebank added the A-impl-trait Area: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch. label Nov 15, 2018
jonhoo added a commit to jonhoo/msql-srv that referenced this issue Dec 4, 2018
@Arnavion
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.

@Centril Centril added F-type_alias_impl_trait `#[feature(type_alias_impl_trait)]` requires-nightly This issue requires a nightly compiler in some way. labels Jul 28, 2019
Dylan-DPC-zz pushed a commit to Dylan-DPC-zz/rust that referenced this issue Mar 19, 2020
…ikomatsakis

Add regression test for TAIT lifetime inference (issue rust-lang#55099)

Fixes rust-lang#55099

The minimized reproducer in issue rust-lang#55099 now compiles successfully.
This commit adds a regression test for it.
JohnTitor added a commit to JohnTitor/rust that referenced this issue Mar 20, 2020
…ikomatsakis

Add regression test for TAIT lifetime inference (issue rust-lang#55099)

Fixes rust-lang#55099

The minimized reproducer in issue rust-lang#55099 now compiles successfully.
This commit adds a regression test for it.
bors added a commit to rust-lang-ci/rust that referenced this issue Mar 20, 2020
Rollup of 9 pull requests

Successful merges:

 - rust-lang#69618 (Clarify the relationship between `forget()` and `ManuallyDrop`.)
 - rust-lang#69768 (Compute the correct layout for variants of uninhabited enums)
 - rust-lang#69935 (codegen/mir: support polymorphic `InstanceDef`s)
 - rust-lang#70103 (Clean up E0437 explanation)
 - rust-lang#70131 (Add regression test for TAIT lifetime inference (issue rust-lang#55099))
 - rust-lang#70133 (remove unused imports)
 - rust-lang#70145 (doc: Add quote to .init_array)
 - rust-lang#70146 (Clean up e0438 explanation)
 - rust-lang#70150 (triagebot.toml: accept cleanup-crew)

Failed merges:

r? @ghost
@bors bors closed this as completed in fda913b Mar 20, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-impl-trait Area: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch. A-lifetimes Area: Lifetimes / regions F-type_alias_impl_trait `#[feature(type_alias_impl_trait)]` requires-nightly This issue requires a nightly compiler in some way.
Development

Successfully merging a pull request may close this issue.

4 participants