Presenting "lifetime inference" errors better in NLL


#21

I opened https://github.com/rust-lang/rust/pull/52168/ – as the PR says, open to changing the wording further, but this logic helps to find a good place to highlight, in any case.


#22

I like this idea – seems concise yet relatively clear.


#23

For brainstorming purposes, I decided to try rewriting the suggested error message in the most explicit, non-technical language I could manage. I’m not sure how to reduce this to something we’d actually use, but maybe it can give someone ideas:

error: we need to infer a lifetime to use, but a lifetime here has requirements
that contradict each other
  --> underscore-lifetime/dyn-trait-underscore.rs:18:5
   |
16 | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> {
   |         -----------     -------------------------- when you use `dyn Trait` in this
      context, it's implicitly `dyn Trait + 'static`, so this type is equivalent to
      `Box<dyn Iterator<Item = &T> + 'static>`
   |         |
   |         when you use & without an explicit lifetime, it still has a lifetime,
             even though that lifetime isn't named. Let's call this lifetime `'1`.
             So we can write the type of `items` as `&'1 [T]`.
17 |     Box::new(items.iter())
   |     ^^^^^^^^^^^^^^^^^^^^^^ casting a `Box<std::slice::Iter<'1, T>>` value
         to `Box<dyn Iterator<Item = &T> + 'static>` is only possible if
         `std::slice::Iter<'1, T>` obeys the trait bounds `Iterator<Item = &T> + 'static`.
         And that only happens if '1 includes 'static`.
         But the function signature allows '1 to be smaller than 'static.

#24

Would it be possible use borrowchecker in “reverse” mode and instead of guarding against error… generate bad code (in compiler error explanation of course)? For example, for function, which returns reference to local variable, generate code which calls this function and mark up “here you have reference but actual variable was disposed over there”. or even better, create a timeline with var created(line N), var disposed(line N), var reference returned (line N) var use after dispose (line N) oops!. Because this is the process we do in our mind. Get hit by compiler error message, find rule which we violate and try to guess, what is it compiler is trying us to safe from. In non trivial cases this guessing is hard. If compiler could show us code which would cause dangling reference, it would lead developers straight to the finish line of understanding error root cause. After all, we do not need rules, but “what could go wrong”.