# Presenting "lifetime inference" errors better in NLL

**URL:** <https://internals.rust-lang.org/t/presenting-lifetime-inference-errors-better-in-nll/7881>\
**Category:** compiler\
**Created:** [July 5, 2018, 1:38am UTC](https://internals.rust-lang.org/t/presenting-lifetime-inference-errors-better-in-nll/7881 "2018-07-05T01:38:22Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![nikomatsakis](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nikomatsakis/32/5410_2.png) [@nikomatsakis](https://internals.rust-lang.org/u/nikomatsakis)\
**Post date:** [July 5, 2018, 1:38am UTC](https://internals.rust-lang.org/t/presenting-lifetime-inference-errors-better-in-nll/7881/1 "2018-07-05T01:38:22Z")

</div>

So, one of the big topics in NLL is how to handle lifetime errors – specifically, I am taking aim at that class of errors that currently show up as “unable to infer lifetime for foo”. I want to see if, with NLL, we can do a better job of presenting that information. We’ve been working on a template for such errors and I’d like to get some feedback.

Here is an example test:

```rust
fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> {
    Box::new(items.iter())
}

```

Here is the current error message that you get when you try to compile this test:

```rust
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
  --> underscore-lifetime/dyn-trait-underscore.rs:18:20
   |
17 | Box::new(items.iter())
   | ^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the function body at 16:1...
  --> underscore-lifetime/dyn-trait-underscore.rs:16:1
   |
16 | / fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> {
17 | | Box::new(items.iter())
17 | | }
   | |_^
note: ...so that reference does not outlive borrowed content
  --> underscore-lifetime/dyn-trait-underscore.rs:18:14
   |
17 | Box::new(items.iter())
   | ^^^^^
   = note: but, the lifetime must be valid for the static lifetime...
   = note: ...so that the expression is assignable:
           expected std::boxed::Box<(dyn std::iter::Iterator<Item=&T> + 'static)>
              found std::boxed::Box<dyn std::iter::Iterator<Item=&T>>

```

My experience has been that most people just have their eyes glaze over when confronted with all this stuff.

### General plan

In general, my plan for region errors is two-fold:

- First, we should identify as many special cases as we can and give highly tailored messages.
- _But_ we also need a general fallback plan.

It’s the latter point I want to talk about here: a kind of general fallback for region errors when we don’t have a specific error message at hand. I think this “general plan” probably can also have a number of smaller helpful notes that we add from time to time (in fact, my example below has one).

### A new template for general errors

Before I explain how my new template for “general errors” works, let me show you how it might look on the error above. I want to give you this first so as not to bias you:

```rust
error: unsatisfied lifetime constraints
  --> underscore-lifetime/dyn-trait-underscore.rs:18:5
   |
16 | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> {
   | ----- -------------------------- defaults to: `Box<dyn Iterator<Item = &T> + 'static>`
   | |
   | the fully elaborated type of `items` is `&'1 [T]`
17 | Box::new(items.iter())
   | ^^^^^^^^^^^^^^^^^^^^^^ casting this value to `Box<dyn Iterator<Item = &T>>` requires `'1` to be `'static`

```

The basic plan here:

- first, to first give names to anonymous lifetimes via “fully elaborated types”. So here the lifetime of the `items` argument is “elaborated” and named `'1` – this is intentionally not valid syntax, for a variety of reasons.
- second, to identify key points within the function and talk about the constraints they introduce. In this case, the point we identify is the cast to `Box<dyn Iterator<Item = &T>>`, but in general there may be more than one such case
- third, try to add add’l helpful tips for defaults and things that may not be obvious, such as the fact that `Box<dyn Iterator>` defaults to `Box<dyn Iterator + 'static>`

This error message feels _much_ better than the original, but still ungreat. It feels like a system that one could learn to understand as you become more experienced, but is probably not very good for newbies. That’s progress – and I’ll take it – but it’d be nice if we could do better.

Anyway, I wanted to open up this thread to chat with folks (cc @davidtwco, @ekuber) and try to brainstorm how we might do better here.

### Implementation plan

In terms of implementation, I am hoping to land [https://github.com/rust-lang/rust/pull/52021](https://github.com/rust-lang/rust/pull/52021) ASAP, which lays some of the foundation here. Then I thought I would open up some issues and try to keep things moving towards the error I gave above. In the meantime, maybe we can discuss come up with a better overall system for talking about these sorts of errors, and we can adjust things to match.

---

<div class="post-metadata">

**Author:** ![nikomatsakis](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nikomatsakis/32/5410_2.png) [@nikomatsakis](https://internals.rust-lang.org/u/nikomatsakis)\
**Post date:** [July 5, 2018, 1:41am UTC](https://internals.rust-lang.org/t/presenting-lifetime-inference-errors-better-in-nll/7881/2 "2018-07-05T01:41:07Z")

</div>

One immediate thing here is that we might special case regions, like the one in this example, that are the lifetime of the “main reference”. i.e., if we have an argument `foo: &T` and we are talking about the lifetime of that reference, we can maybe just talk about "lifetime of `foo`" instead of giving it a numbered name.

Example:

```rust
error: unsatisfied lifetime constraints
  --> underscore-lifetime/dyn-trait-underscore.rs:18:5
   |
16 | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> {
   | -------------------------- defaults to: `Box<dyn Iterator<Item = &T> + 'static>`
17 | Box::new(items.iter())
   | ^^^^^^^^^^^^^^^^^^^^^^ casting this value to `Box<dyn Iterator<Item=&T>>` requires `items` to have `'static` lifetime

```

---

<div class="post-metadata">

**Author:** ![nikomatsakis](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nikomatsakis/32/5410_2.png) [@nikomatsakis](https://internals.rust-lang.org/u/nikomatsakis)\
**Post date:** [July 5, 2018, 2:07am UTC](https://internals.rust-lang.org/t/presenting-lifetime-inference-errors-better-in-nll/7881/3 "2018-07-05T02:07:47Z")

</div>

Some things I am not keen on:

- “unsatisfied lifetime constraints” as the header
  - probably this should be drawn instead from the “primary” error

- the phrase “fully elaborated type” – I like the idea, but it feels jargon-y. I can’t think of a better way to present such types though.
  - I do wonder if the `--explain` can explain “how to read” these errors, and if that might help a bit?

---

<div class="post-metadata">

**Author:** ![ekuber](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ekuber/32/1646_2.png) [@ekuber](https://internals.rust-lang.org/u/ekuber)\
**Post date:** [July 5, 2018, 6:09am UTC](https://internals.rust-lang.org/t/presenting-lifetime-inference-errors-better-in-nll/7881/4 "2018-07-05T06:09:39Z")

</div>

> [@nikomatsakis](#):
>
> - “unsatisfied lifetime constraints” as the header
> - probably this should be drawn instead from the “primary” error

I feel the best option we have is to land the PR and iterate over it, the foundation there is good enough to work with.

> [@](#):
>
> - the phrase “fully elaborated type” – I like the idea, but it feels jargon-y. I can’t think of a better way to present such types though.

This is a problem throughout a lot of diagnostics... We have to unify the messaging. I'm trying to take inspiration from the book, but this is probably we should sit down with Steve, Oli and Jonathan to brainstorm how to refer to these concepts without using jargon.

> [@](#):
>
> - I do wonder if the `--explain` can explain “how to read” these errors, and if that might help a bit?

The only problem I see is the explosion of variations of lifetime errors we give. They are great in that the well trodden path usually has great, very specific readable diagnostics, but it does make it harder to write documentation for them. That said, at least we can refer to the diagnostic code to see all the variations that we're aware of, so maybe that's a silver lining?

> [@nikomatsakis](#):
>
> - first, to first give names to anonymous lifetimes via “fully elaborated types”. So here the lifetime of the `items` argument is “elaborated” and named `'1` – this is intentionally not valid syntax, for a variety of reasons.

I'm not sure what I think of this. Giving them a name to be able to refer to them seems like an easy solution to the "how do we talk about anonymous lifetimes" problem, but I feel that it'll pay off to search for wording that will not _require_ naming them. (This presumes that such a wording can be found.)

> [@](#):
>
> - second, to identify key points within the function and talk about the constraints they introduce. In this case, the point we identify is the cast to `Box<dyn Iterator<Item = &T>>` , but in general there may be more than one such case
> - third, try to add add’l helpful tips for defaults and things that may not be obvious, such as the fact that `Box<dyn Iterator>` defaults to `Box<dyn Iterator + 'static>`

I feel that that is something that can be done through suggestions, but I also question the possibility of changing the ergonomics of the language to assume `+ '_` instead of `'static` for the snippet shown.

---

<div class="post-metadata">

**Author:** ![nikomatsakis](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nikomatsakis/32/5410_2.png) [@nikomatsakis](https://internals.rust-lang.org/u/nikomatsakis)\
**Post date:** [July 5, 2018, 10:43am UTC](https://internals.rust-lang.org/t/presenting-lifetime-inference-errors-better-in-nll/7881/5 "2018-07-05T10:43:50Z")

</div>

Another few attempts.

The first one is more generic, the second more specialized:

```rust
error: `'static` lifetime required
  --> underscore-lifetime/dyn-trait-underscore.rs:18:5
   |
16 | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> {
   | ----- -------------------------- defaults to: `Box<dyn Iterator<Item = &T> + 'static>`
   | |
   | fully elaborated type of `items` is `&'1 [T]`
17 | Box::new(items.iter())
   | ^^^^^ `'1` is cast into to a `dyn Iterator` type with a `'static` bound

```

A more specialized attempt follows. This one relies on us observing that `'1` is the argument of a reference and then choosing to conflate `items` with the name of the lifetime:

```rust
error: `items` required to have `'static` lifetime
  --> underscore-lifetime/dyn-trait-underscore.rs:18:5
   |
16 | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> {
   | ----- -------------------------- defaults to: `Box<dyn Iterator<Item = &T> + 'static>`
   | |
   | `items` declared here
17 | Box::new(items.iter())
   | ^^^^^ `items` is cast into a `dyn Iterator` type with a `'static` bound

```

Some thoughts about how we might generate this:

- First, you see that I am highlighting the use of `items` in both cases, instead of the entire `Box::new(items.iter())` expression:
  - I think we can use the fact that `'1` (the error region) appears in `items` to cause us to consider uses of that same variable in MIR as more significant.

- Second, I have suppressed the highlighting of the “implicit cast” that is occurring at the return:
  - This seems like just noise.

- Third, I am identifying arguments of `&T` type and printing the argument name instead of a synthetic variable
- Fourth, I changed the message around casts (there are many other cases, we should try to come up with a more comprehensive set of examples) to “R1 is cast into a `dyn Foo` type with a R2 bound”

---

<div class="post-metadata">

**Author:** ![nikomatsakis](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nikomatsakis/32/5410_2.png) [@nikomatsakis](https://internals.rust-lang.org/u/nikomatsakis)\
**Post date:** [July 5, 2018, 10:51am UTC](https://internals.rust-lang.org/t/presenting-lifetime-inference-errors-better-in-nll/7881/6 "2018-07-05T10:51:31Z")

</div>

> [@ekuber](#):
>
> This is a problem throughout a lot of diagnostics… We have to unify the messaging. I’m trying to take inspiration from the book, but this is probably we should sit down with Steve, Oli and Jonathan to brainstorm how to refer to these concepts without using jargon.

Yes..I have been wanting to go over the NLL errors **in particular** and try to whittle down and reduce the amount of terminology involved.

> [@ekuber](#):
>
> The only problem I see is the explosion of variations of lifetime errors we give.

One thing I have noticed in the compiler is that when the smart errors are wrong, they give too little information. For example, @tmandry was recently showing me this error:

```rust
error[E0621]: explicit lifetime required in the type of `tcx`
  --> librustc_traits/implied_outlives_bounds.rs:43:5
   |
37 | tcx: TyCtxt<'_, 'tcx, 'tcx>,
   | --- consider changing the type of `tcx` to `rustc::ty::TyCtxt<'tcx, 'tcx, 'tcx>`
...
43 | / tcx.infer_ctxt()
44 | | .enter_canonical_trait_query(&goal, |infcx, fulfill_cx, key| {
45 | | let (param_env, ty) = key.into_parts();
46 | | compute_implied_outlives_bounds(&infcx, param_env, ty)
47 | | })
   | | _________ ^ lifetime `'tcx` required

```

the problem here was that `compute_implied_outlives_bounds` had the wrong type (it was `InferCtxt<'_, 'tcx, 'tcx>` and should have been `InferCtxt<'_, 'gcx, 'tcx>`).

I think the compiler's suggestion was good, but it would have been _better_ if it could've included more tips on how it came to its conclusions.

This suggests to me that my premise of "specialized errors" is a bit flawed -- that is, the ideal might be if more and more we can **incorporate** the specialized errors into the same basic framework for reporting region errors, so that we can _also_ have information about how the compiler came to its conclusions.

> [@ekuber](#):
>
> I’m not sure what I think of this. Giving them a name to be able to refer to them seems like an easy solution to the “how do we talk about anonymous lifetimes” problem, but I feel that it’ll pay off to search for wording that will not _require_ naming them. (This presumes that such a wording can be found.)

Yeah, I've been going back and forth. I think my conclusion is sort of the same but I look at it differently. That is, giving them names is very hard, because it's hard to find a wording for it. **But** if we can find a way to give them names, it'll make almost everything easier.

That said, names like `'1` seem like they are just going to be sort of inherently confusing, which is why I've been toying with using the variable name etc.

But still, without some anonymous names, I don't know how to handle cases like identifying the second argument of `TyCtxt<'_, '_, 'tcx>`.

---

<div class="post-metadata">

**Author:** ![nikomatsakis](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nikomatsakis/32/5410_2.png) [@nikomatsakis](https://internals.rust-lang.org/u/nikomatsakis)\
**Post date:** [July 5, 2018, 11:04am UTC](https://internals.rust-lang.org/t/presenting-lifetime-inference-errors-better-in-nll/7881/7 "2018-07-05T11:04:05Z")

</div>

Some experiments around wording. Specifically, if we _did_ want to give a name. I’m consider this example but I’m thinking actually of stuff like `TyCtxt`:

- fully elaborated type is `TyCtxt<'1, 'gcx, 'tcx>`

The problem is that I feel like what is missing is some kind of “intro” explaining how these errors work, but I can’t think of a _short_ way to do that. I keep thinking of stuff like this:

```rust
16 | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> {
   | -----
   | |
   | the error concerns a lifetime that appears in `items` which we'll call `'1`
   | the type of `items` is then `&'1 [T]`

```

Maybe:

```rust
16 | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> {
   | -----
   | |
   | consider the lifetime denoted `'1` in the type `&'1 [T]`

```

Ah, one interesting observation. It’ll be hard to take advantage of it, **but** :

- In Rust 2018, most anonymous lifetimes **have** some kind of syntactic marker: it is either `'_` or an `&`.

That means we could do something like this:

```rust
16 | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> {
   | - let's call the lifetime of this reference `'1`

```

The resulting error:

```rust
error: `'static` lifetime required
  --> underscore-lifetime/dyn-trait-underscore.rs:18:5
   |
16 | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> {
   | - -------------------------- defaults to: `Box<dyn Iterator<Item = &T> + 'static>`
   | |
   | let's call the lifetime of this reference `'1`
17 | Box::new(items.iter())
   | ^^^^^ `'1` is cast into to a `dyn Iterator` type with a `'static` bound

```

Similarly you might have:

```rust
error[E0621]: `'tcx` lifetime required
  --> librustc_traits/implied_outlives_bounds.rs:43:5
   |
37 | tcx: TyCtxt<'_, 'tcx, 'tcx>,
   | -- let's call this lifetime `'1`
...
43 | / tcx.infer_ctxt()
44 | | .enter_canonical_trait_query(&goal, |infcx, fulfill_cx, key| {
45 | | let (param_env, ty) = key.into_parts();
46 | | compute_implied_outlives_bounds(&infcx, param_env, ty)
47 | | })
   | | _________ ^ `'1` is required to be `'tcx` here
   |
   | = help: consider changing the type of `tcx` to `rustc::ty::TyCtxt<'tcx, 'tcx, 'tcx>`

```

---

<div class="post-metadata">

**Author:** ![earthengine](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/earthengine/32/2577_2.png) [@earthengine](https://internals.rust-lang.org/u/earthengine)\
**Post date:** [July 5, 2018, 11:31am UTC](https://internals.rust-lang.org/t/presenting-lifetime-inference-errors-better-in-nll/7881/8 "2018-07-05T11:31:50Z")

</div>

> [@nikomatsakis](#):
>
> “unsatisfied lifetime constraints”

My idea: “unsatisfied lifetime constraints” =\>

- "lifetime requirements conflicts" : when lifetimes are named but have conflict requirements

- "unnamed lifetime cannot be derived": when one or more unnamed lifetime cannot be derived from constraints

---

<div class="post-metadata">

**Author:** ![nikomatsakis](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nikomatsakis/32/5410_2.png) [@nikomatsakis](https://internals.rust-lang.org/u/nikomatsakis)\
**Post date:** [July 5, 2018, 11:43am UTC](https://internals.rust-lang.org/t/presenting-lifetime-inference-errors-better-in-nll/7881/9 "2018-07-05T11:43:32Z")

</div>

> [@earthengine](#):
>
> “unnamed lifetime cannot be derived”: when one or more unnamed lifetime cannot be derived from constraints

I think this leads one to an inaccurate mental model -- that is, the values of unnamed lifetimes (e.g., `items: &u32`) are not being _inferred_ by the compiler. Rather, we are making sure that `items: &u32` will be valid for **any lifetime** that the caller chooses, because the signatures says that the caller can pick any lifetime. But we have found that the **body** only works for the lifetime `'static`.

It is similar to this situation:

```rust
fn foo<T>(t: T) -> u32 {
    t
}

```

That is, here we said "you can give me any type `T` and I will you back a `u32`", but then we are back the variable `t` -- now, sometimes that might be a `u32`, but not always.

That makes me wonder though if we should pursue this line of explanation. Something like:

```rust
error: `'static` lifetime required
  --> underscore-lifetime/dyn-trait-underscore.rs:18:5
   |
16 | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> {
   | -----           
   | |
   | caller of `a` is allowed to pick any lifetime for `items` they want
17 | Box::new(items.iter())
   | ^^^^^ but here `items` must have `'static` lifetime to be cast to `dyn Iterator`
   |
   | help: the return type defaults to `Box<dyn Iterator<Item = &T> + 'static>`
   |
16 | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> {
   | --------------------------

```

(OK, I threw in one of the other experiment, which is pulling out some of the hints to make things a bit less busy.)

---

<div class="post-metadata">

**Author:** ![nikomatsakis](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nikomatsakis/32/5410_2.png) [@nikomatsakis](https://internals.rust-lang.org/u/nikomatsakis)\
**Post date:** [July 5, 2018, 11:44am UTC](https://internals.rust-lang.org/t/presenting-lifetime-inference-errors-better-in-nll/7881/10 "2018-07-05T11:44:49Z")

</div>

One other thing: I have historically felt (and continue to feel!) that lifetime was a poor choice to use here. So I would like to see if we can rework the error messages not to use that word. I think it leads to bad intuitions, since it suggests the “lifetime of the underlying value”. Have to go look at the messages again.

---

<div class="post-metadata">

**Author:** ![mark-i-m](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mark-i-m/32/3167_2.png) [@mark-i-m](https://internals.rust-lang.org/u/mark-i-m)\
**Post date:** [July 5, 2018, 4:43pm UTC](https://internals.rust-lang.org/t/presenting-lifetime-inference-errors-better-in-nll/7881/11 "2018-07-05T16:43:04Z")

</div>

Thanks @nikomatsakis!

> [@nikomatsakis](#):
>
> Some things I am not keen on:
> 
> - “unsatisfied lifetime constraints” as the header
> - probably this should be drawn instead from the “primary” error
> 
> - the phrase “fully elaborated type” – I like the idea, but it feels jargon-y. I can’t think of a better way to present such types though.
> - I do wonder if the `--explain` can explain “how to read” these errors, and if that might help a bit?

I personally don't think "unsatisfied lifetime constraints" or "fully elaborated type" are very problematic. People will learn the jargon. We could try to soften it, but IMHO that's where the effort should be spent.

What would stump me is things like `defaults to: `Box<dyn Iterator<Item = &T> + 'static>` `. It would take me a while to figure out where the default of `'static` comes from and why. In this case, it's easy enough, but in general, I have always had trouble figuring out where some of the defaults/inferred values come from.

---

<div class="post-metadata">

**Author:** ![nikomatsakis](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nikomatsakis/32/5410_2.png) [@nikomatsakis](https://internals.rust-lang.org/u/nikomatsakis)\
**Post date:** [July 5, 2018, 4:50pm UTC](https://internals.rust-lang.org/t/presenting-lifetime-inference-errors-better-in-nll/7881/12 "2018-07-05T16:50:02Z")

</div>

> [@mark-i-m](#):
>
> It would take me a while to figure out where the default of `'static` comes from and why.

So, what could we do to improve that, you think? (Leaving aside the question fo changing the language that @ekuber raised -- I forgot to reply to that, but I think I'd prefer to focus here on just error messages; in any case, that default was not arrived at lightly, and I am reluctant to change it)

In this case, the reason for that is .. kind of just ... "those are the rules". It seems like it'd be nice if we could give a link to a more detailed explanation -- this is where the `--teach` mode would be **awesome**. But we don't have that.

This is one reason I was moving more towards a "separate note" vs an inline note. In particular, it would give us room to say a bit more, such as:

> `dyn Trait` types have a default lifetime bound of `'static`

(That's not _quite_ right, the real rule is that their lifetime bound is `'static` unless they appear inside a reference, so I have to think how to word it more precisely.)

Perhaps:

* * *

```rust
= note: the `dyn Iterable` type has a default bound of `'static`
    in the type `Box<dyn Iterable<Item = &T>>`, 
    so the return type here is equivalent to:
 
 | Box<dyn Iterable<Item = &T> + 'static>

```

or something...?

---

<div class="post-metadata">

**Author:** ![davidtwco](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/davidtwco/32/10027_2.png) [@davidtwco](https://internals.rust-lang.org/u/davidtwco)\
**Post date:** [July 5, 2018, 5:05pm UTC](https://internals.rust-lang.org/t/presenting-lifetime-inference-errors-better-in-nll/7881/13 "2018-07-05T17:05:48Z")

</div>

One idea I've had, and I'm not sure if it's something we _can_ do (or _should_ do), would be to insert `'1` into the argument in the span and highlight it with a colour to emphasise that it is an addition for the purpose of the error message?

That is, instead of:

```rust
error: unsatisfied lifetime constraints
  --> underscore-lifetime/dyn-trait-underscore.rs:18:5
   |
16 | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> {
   | ----- -------------------------- defaults to: `Box<dyn Iterator<Item = &T> + 'static>`
   | |
   | the fully elaborated type of `items` is `&'1 [T]`
17 | Box::new(items.iter())
   | ^^^^^^^^^^^^^^^^^^^^^^ casting this value to `Box<dyn Iterator<Item = &T>>` requires `'1` to be `'static`

```

We would show (but the `'1` is in some colour to indicate that it is new):

```rust
error: unsatisfied lifetime constraints
  --> underscore-lifetime/dyn-trait-underscore.rs:18:5
   |
16 | fn a<T>(items: &'1 [T]) -> Box<dyn Iterator<Item=&T>> {
   | -------------------------- defaults to: `Box<dyn Iterator<Item = &T> + 'static>`
17 | Box::new(items.iter())
   | ^^^^^^^^^^^^^^^^^^^^^^ casting this value to `Box<dyn Iterator<Item = &T>>` requires `'1` to be `'static`

```

I'm pretty certain that this is an awful idea, but you never know, it might inspire something in someone reading.

* * *

> [@nikomatsakis](#):
>
> The first one is more generic, the second more specialized:

I think the specialized example shown in this message is perhaps my favourite iteration on the error message seen thus far, perhaps the only downside I see is that mentioned by @mark-i-m whereby `defaults to: `Box<dyn Iterator<Item = &T> + 'static>` isn't immediately obvious where the `'static` comes from - I'm not sure what the best way to explain this in the error is though. I also agree that terminology such as "fully elaborated type" isn't too confusing or unclear.

---

<div class="post-metadata">

**Author:** ![nikomatsakis](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nikomatsakis/32/5410_2.png) [@nikomatsakis](https://internals.rust-lang.org/u/nikomatsakis)\
**Post date:** [July 5, 2018, 5:23pm UTC](https://internals.rust-lang.org/t/presenting-lifetime-inference-errors-better-in-nll/7881/14 "2018-07-05T17:23:26Z")

</div>

> [@davidtwco](#):
>
> I’m pretty certain that this is an awful idea

Interesting idea. regardless, I think doing what I suggested is probably a good first step -- that is, we have to write the code to _identify_ the place where the lifetime would go.

It's also worth pointing out that this won't apply in all cases, particularly around closures. For example, there is no explicit type on `x` here:

```rust
|x| foo(x)

```

so if we want to show the elaborated type of `x: &'1 u32`, we can't do it by highlighting the existing code etc. So we probably need the "fully elaborated type" sort of phrasing as a fallback anyway. I like the "let's call" terminology though -- you could imagine

```rust
3 | something(|x| foo(x))
  | ^ let's call the type here `TyCtxt<'1, '_, '_>`

```

Another such example would be upvars; this closure may need to annotate `x`:

```rust
let x = ...;
foo(|| use(x))

```

---

<div class="post-metadata">

**Author:** ![mark-i-m](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mark-i-m/32/3167_2.png) [@mark-i-m](https://internals.rust-lang.org/u/mark-i-m)\
**Post date:** [July 5, 2018, 5:33pm UTC](https://internals.rust-lang.org/t/presenting-lifetime-inference-errors-better-in-nll/7881/15 "2018-07-05T17:33:06Z")

</div>

Yes, that is a significant improvement. In particular, it makes it clear that the error is due to a bug in the program, rather than forgetting to specifying a lifetime or something. I would be perfectly fine with seeing “'cause that’s the rules in an error message” as opposed to “because type Foo specifies lifetime 'static”.

---

<div class="post-metadata">

**Author:** ![Eh2406](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/eh2406/32/4839_2.png) [@Eh2406](https://internals.rust-lang.org/u/Eh2406)\
**Post date:** [July 5, 2018, 6:42pm UTC](https://internals.rust-lang.org/t/presenting-lifetime-inference-errors-better-in-nll/7881/16 "2018-07-05T18:42:00Z")

</div>

In the tradition of bad ideas...

> [@nikomatsakis](#):
>
> So we probably need the “fully elaborated type” sort of phrasing as a fallback anyway.

If we are uneliding things from the code anyway then we can just do:

```rust
3 | something(|x: TyCtxt<'1, '_, '_>| foo(x))

```

and similarly for upvars

```rust
let x: TyCtxt<'1, '_, '_> = ...;
foo(|| use(x))

```

---

<div class="post-metadata">

**Author:** ![nikomatsakis](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nikomatsakis/32/5410_2.png) [@nikomatsakis](https://internals.rust-lang.org/u/nikomatsakis)\
**Post date:** [July 6, 2018, 2:08pm UTC](https://internals.rust-lang.org/t/presenting-lifetime-inference-errors-better-in-nll/7881/17 "2018-07-06T14:08:16Z")

</div>

OK, so let me try to break this down to some immediate next steps. These are basically things to do to improve [my existing PR #52021](https://github.com/rust-lang/rust/pull/52021):

- code to find and highlight the precise part of the type where a region appears
  - i.e., to say something like "let’s call the lifetime of this reference `'1`"
  - seems like no matter what we’re going to want this

- code to identify when we are casting to a trait object with a default bound

hmm, ok, that was not as good a list as I hoped. have to come back to this. posting this message anyway to get it out of my “queue” 🙂

---

<div class="post-metadata">

**Author:** ![lambda](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/lambda/32/292_2.png) [@lambda](https://internals.rust-lang.org/u/lambda)\
**Post date:** [July 7, 2018, 5:24am UTC](https://internals.rust-lang.org/t/presenting-lifetime-inference-errors-better-in-nll/7881/18 "2018-07-07T05:24:40Z")

</div>

> [@nikomatsakis](#):
>
> ```rust
> error: unsatisfied lifetime constraints
> --> underscore-lifetime/dyn-trait-underscore.rs:18:5
> |
> 16 | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> {
> | ----- -------------------------- defaults to: `Box<dyn Iterator<Item = &T> + 'static>`
> | |
> | the fully elaborated type of `items` is `&'1 [T]`
> 17 | Box::new(items.iter())
> | ^^^^^^^^^^^^^^^^^^^^^^ casting this value to `Box<dyn Iterator<Item = &T>>` requires `'1` to be `'static`
> 
> ```

Thoughts on the initial suggestion:

1. A good start, less extra verbiage for eyes to glaze over
2. Too wide. Have to scroll horizontally to see the messages. Wider than my usual terminals and editor windows, so would wrap badly
3. "fully elaborated type" is too jargony, and also just too verbose
4. While this is a lot less for the eyes to glaze over, it's still quite a "garden path" in which I need to look over several places and combine information to figure out what's going on

After looking at some of the later suggestions, I think that the jargony nature may not actually be the issue, but just the length. Any amount of prose moves the elaborated type fairly far away from what it's labeling making it harder to read.

> [@nikomatsakis](#):
>
> ```rust
> 3 | something(|x| foo(x))
> | ^ let's call the type here `TyCtxt<'1, '_, '_>`
> 
> ```

I think you might be able to get away with something much shorter, like:

```rust
3 | something(|x| foo(x))
  | ^ called `TyCtxt<'1, '_, '_>`

```

Or applied to the original example:

```rust
error: unsatisfied lifetime constraints
  --> underscore-lifetime/dyn-trait-underscore.rs:18:5
   |
16 | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> {
   | ---- -------------------------- 
   | | defaults to `Box<dyn Iterator<Item = &T> + 'static>`
   | called `&'1 [T]`
   |
17 | Box::new(items.iter())
   | ^^^^^^^^^^^^^^^^^^^^^^
   | return type `Box<dyn Iterator<Item = &T> + 'static>` requires `'1` to be `'static`

```

I'm not entirely satisfied with that result, but I do find I can see a lot more of the relevant information quickly, and closer to the relevant code, than I could with all of the extra prose.

---

<div class="post-metadata">

**Author:** ![Tom-Phinney](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tom-phinney/32/3299_2.png) [@Tom-Phinney](https://internals.rust-lang.org/u/Tom-Phinney)\
**Post date:** [July 7, 2018, 6:46am UTC](https://internals.rust-lang.org/t/presenting-lifetime-inference-errors-better-in-nll/7881/19 "2018-07-07T06:46:24Z")

</div>

Rather than

> ^ called `TyCtxt&lt;'1, '_, '_&gt;`

how about

> ^ here called `TyCtxt&lt;'1, '_, '_&gt;`

To me that makes clear both the referent and the explanatory substitution.

---

<div class="post-metadata">

**Author:** ![illustrious-you](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/illustrious-you/32/3960_2.png) [@illustrious-you](https://internals.rust-lang.org/u/illustrious-you)\
**Post date:** [July 8, 2018, 1:10pm UTC](https://internals.rust-lang.org/t/presenting-lifetime-inference-errors-better-in-nll/7881/20 "2018-07-08T13:10:37Z")

</div>

> [@lambda](#):
>
> “fully elaborated type” is too jargony, and also just too verbose

A few ideas: exact, definite, or complete type.

```rust
error: unsatisfied lifetime constraints
  --> underscore-lifetime/dyn-trait-underscore.rs:18:5
   |
16 | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> {
   | ----- -------------------------- defaults to: `Box<dyn Iterator<Item = &T> + 'static>`
   | |
   | the exact type of `items` is `&'1 [T]`
17 | Box::new(items.iter())
   | ^^^^^^^^^^^^^^^^^^^^^^ casting this value to `Box<dyn Iterator<Item = &T>>` requires `'1` to be `'static`

```

[Next page](https://internals.rust-lang.org/t/presenting-lifetime-inference-errors-better-in-nll/7881.md?page=2)
