Repository: rust
Issue: Confusing error message when returning impl Trait with multiple lifetimes
Labels: C-enhancement,A-diagnostics,A-lifetimes,T-compiler,A-impl-trait

Given

```rust
use std::fmt::Debug;

fn foobar<'a, 'b>(foo: &'a str, bar: &'b str) -> impl Debug + 'a + 'b {
    (foo, bar)
}

fn main() {
    let foo = "hello".to_owned();
    let bar = "world".to_owned();
    println!("{:?}", foobar(&foo, &bar));
}
```

you currently (`rustc 1.26.0-nightly (188e693b3 2018-03-26)`) get the errors

```
error[E0623]: lifetime mismatch
 --> foo.rs:3:50
  |
3 | fn foobar<'a, 'b>(foo: &'a str, bar: &'b str) -> impl Debug + 'a + 'b {
  |                                      -------     ^^^^^^^^^^^^^^^^^^^^
  |                                      |           |
  |                                      |           ...but data from `foo` is returned here
  |                                      this parameter and the return type are declared with different lifetimes...

error[E0623]: lifetime mismatch
 --> foo.rs:3:50
  |
3 | fn foobar<'a, 'b>(foo: &'a str, bar: &'b str) -> impl Debug + 'a + 'b {
  |                        -------                   ^^^^^^^^^^^^^^^^^^^^
  |                        |                         |
  |                        |                         ...but data from `bar` is returned here
  |                        this parameter and the return type are declared with different lifetimes...
```

This not being an allowed syntax was briefly [mentioned by @nikomatsakis](https://github.com/rust-lang/rust/issues/34511#issuecomment-373423999) in #34511, quoting the relevant part of the comment: 

> This is kind of annoying to do; we can't use `'cx + 'gcx`. We can I suppose make a dummy trait:
> 
> ```rust
> trait Captures<'a> { }
> impl<T: ?Sized> Captures<'a> for T { }
> ```
>
> and then return something like this `impl Iterator<Item = &'tcx Foo> + Captures<'gcx> + Captures<'cx>`.

As far as I recall/can discover this limitation was never followed up on in that thread.

---

After some RFC spelunking I cannot find anything restricting a type bound to having at most a single lifetime bound, [RFC 192 Appendix B](https://github.com/rust-lang/rfcs/blob/90a6f4e6901277e90f333e8228bef68a0db2e492/text/0192-bounds-on-object-and-generic-types.md#appendix-b-why-object-types-must-have-exactly-one-bound) may be relevant, but I don't believe that the `Trait` part of `impl Trait` is an "object type", it seems to me to be a "type parameter bound". Re-reading the `impl Trait` RFC series doesn't appear to clear this up, exactly what sort of syntax `Trait` is is never explicitly named, the [original RFC](https://github.com/rust-lang/rfcs/blob/master/text/1522-conservative-impl-trait.md#syntax) simply says

> The proposed syntax is `impl Trait` in return type position, composing like trait objects to forms like `impl Foo+Send+'a`.

It seems to me that supporting multiple lifetime bounds on `impl Trait` should be fine, conceptually it seems to be the equivalent of:

```rust
use std::fmt::Debug;

fn foobar<'a, 'b, T: Debug + 'a + 'b>(foo: &'a &'b T) {
    println!("{:?}", foo);
}

fn main() {
    let foo = "hello world";
    {
        let bar = &foo;
        {
            let baz = &bar;
            foobar(baz);
        }
    }
}
```

---

Whether or not `impl Trait` can be extended to support multiple lifetimes, it seems like there should be an error message that the form `impl Foo + 'a + 'b` is not valid currently, rather than some weird lifetime mismatch errors.