Stream: t-compiler/wg-diagnostics

Topic: diagnostics around `for<'a>`


nikomatsakis (Nov 19 2018 at 17:20, on Zulip):

So the PR https://github.com/rust-lang/rust/pull/55517 makes some attempt to give better diagnostics around for<'a> bounds, but there's still lots of room to go.

This feels like an area where I'd love to brainstorm how best to present things.

nikomatsakis (Nov 19 2018 at 17:20, on Zulip):

One thing I found is that we need to do a much better job tracking "how we got to this constraint"

nikomatsakis (Nov 19 2018 at 17:21, on Zulip):

Example of an error for which I would give a "B" grade, roughly:

error: implementation of `Trait` is not general enough
  --> $DIR/hrtb-exists-forall-trait-invariant.rs:28:5
   |
LL |     foo::<()>(); //~ ERROR not general enough
   |     ^^^^^^^^^
   |
   = note: Due to a where-clause on `foo`,
   = note: `()` must implement `Trait<for<'b> fn(std::cell::Cell<&'b u32>)>`
   = note: but `()` only implements `Trait<fn(std::cell::Cell<&'0 u32>)>` for some lifetime `'0`

error: aborting due to previous error
nikomatsakis (Nov 19 2018 at 17:22, on Zulip):

Example where I felt at a loss as to how to do better without having better causal information:

error[E0308]: mismatched types
  --> $DIR/hrtb-exists-forall-fn.rs:17:34
   |
LL |     let _: for<'b> fn(&'b u32) = foo(); //~ ERROR mismatched types
   |                                  ^^^^^ one type is more general than the other
   |
   = note: expected type `for<'b> fn(&'b u32)`
              found type `fn(&u32)`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.
davidtwco (Nov 19 2018 at 17:42, on Zulip):

For the first case, something like this reads a little clearer to me, though it's a tough one:

error: implementation of `Trait` is not general enough
  --> $DIR/hrtb-exists-forall-trait-invariant.rs:28:5
   |
LL |     foo::<()>(); //~ ERROR not general enough
   |     ^^^^^^^^^
   |
   = note: `foo` expects generic type `T` to impl `fn(std::cell::Cell<&'b u32>)` for any lifetime `'b`...
   = note: ...however, `()` implements `Trait` where `T` is `fn(std::cell::Cell<&'b u32>)` for some fixed...
   = note: ...lifetime `'a` - `'a` cannot simultaneously be fixed and equal to any given lifetime `'b`.

error: aborting due to previous error
davidtwco (Nov 19 2018 at 17:54, on Zulip):

Taking a similar idea for the second case:

error[E0308]: mismatched types
  --> $DIR/hrtb-exists-forall-fn.rs:17:34
   |
LL |     let _: for<'b> fn(&'b u32) = foo(); //~ ERROR mismatched types
   |                                  ^^^^^ one type is more general than the other
   |
   = note: expected type `fn(&'b u32)` for any given lifetime `'b` but `foo` is generic over...
   = note: ...a concrete lifetime `'a`. for some invocation of `foo`, `'a` takes on a fixed lifetime...
   = note: ...and so returns `fn(&'a u32)` for that fixed lifetime but is being stored into a variable...
   = note: ...where `'a` would need to equal to any given lifetime `'b`.

error: aborting due to previous error
davidtwco (Nov 19 2018 at 17:55, on Zulip):

Neither is perfect, but maybe it'll inspire a better idea.

nikomatsakis (Nov 19 2018 at 19:59, on Zulip):

foo expects generic type T to impl fn(std::cell::Cell<&'b u32>) for any lifetime 'b...

That doesn't quite sound right to me. That is, () is required to implement the trait Trait<X> for some type X, where the type X is for<'b> fn(Cell<&'b u32).

In other words, I'm not sure what the T is in your message, but whatever it is it cannot "implement" fn, as that is a type, not a trait.

Still, I think there is room for improvement, and the terms "any lifetime" and "some fixed" are perhaps good choices.

davidtwco (Nov 19 2018 at 20:05, on Zulip):

Yeah, my wording is a little off. I tried to hide the for<'a> part and write what that meant in words, and call the rest T (which obviously wouldn't work in an actual error). I think the key thing I felt was beneficial was trying to explain better why the one type is less general - I did that through the "it is/becomes some fixed thing" type of wording.

nikomatsakis (Nov 19 2018 at 20:34, on Zulip):

part of the problem here is that we have to "soup up" the data we have at hand to really be able to tell what happened

nikomatsakis (Nov 19 2018 at 20:34, on Zulip):

but it's good to brainstorm what we want the message to be first

nikomatsakis (Nov 19 2018 at 20:34, on Zulip):

and then figure out how to get the data we need

nikomatsakis (Nov 19 2018 at 20:34, on Zulip):

explaining bindings like this is interesting: it feels particularly hard, although I don't think it's particularly hard for people to understand when explained well

Alexander Regueiro (Dec 17 2018 at 18:03, on Zulip):

Has anyone considered factoring out diagnostics into its own crate in the library? Parts of it are quite a mess right now.

Jake Goulding (Dec 17 2018 at 20:59, on Zulip):

how would such a new crate improve the mess?

Esteban K├╝ber (Dec 17 2018 at 22:30, on Zulip):

Which part of diagnostics would you want as a separate crate?

nikomatsakis (Dec 18 2018 at 20:45, on Zulip):

I've definitely thought about it :)

nikomatsakis (Dec 18 2018 at 20:45, on Zulip):

there exists e.g. https://crates.io/crates/codemap-diagnostic

nikomatsakis (Dec 18 2018 at 20:46, on Zulip):

but I would want us to try to rethink some details of our impl more deeply

nikomatsakis (Dec 18 2018 at 20:46, on Zulip):

still, I think that having separate crates with unit tests etc can be great for maintenance

nikomatsakis (Dec 18 2018 at 20:46, on Zulip):

(but it also induces some burden, our processes aren't always the best here)

Last update: Nov 15 2019 at 11:15UTC