Skip to content

Incorrect inference of lifetime bound for existential type #55099

Closed
@jonhoo

Description

@jonhoo

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-impl-traitArea: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch.A-lifetimesArea: Lifetimes / regionsF-type_alias_impl_trait`#[feature(type_alias_impl_trait)]`requires-nightlyThis issue requires a nightly compiler in some way.

    Type

    No type

    Projects

    Status

    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions