During borrowchecking, we treat any free (early-bound) regions on
the 'defining type' as `RegionClassification::External`. According
to the doc comments, we should only have 'external' regions when
checking a closure/generator.
However, a plain function can also have some if its regions
be considered 'early bound' - this occurs when the region is
constrained by an argument, appears in a `where` clause, or
in an opaque type. This was causing us to incorrectly mark these
regions as 'external', which caused some diagnostic code
to act as if we were referring to a 'parent' region from inside
a closure.
This PR marks all instantiated region variables as 'local'
when we're borrow-checking something other than a
closure/generator/inline-const.
Fixes#67007
Currently, a 'borrowed data escapes' error does not mention
the specific lifetime involved (except indirectly through a suggestion
about adding a lifetime bound). We now explain the specific lifetime
relationship that failed to hold, which improves otherwise vague
error messages.
Fixes#73159
This is similar to #69350 - if the user didn't initially
write out a 'static lifetime, adding 'static in response to
a lifetime error is usually the wrong thing to do.
Currently, `coerce_inner` discards its `ObligationCause`
when calling `try_coerce`. This interfers with other
diagnostc improvements I'm working on, since we will lose
the original span by the time the actual coercion occurs.
Additionally, we now use the span of the trailing expression
(rather than the span of the entire function) when performing
a coercion in `check_return_expr`. This currently has no visible
effect on any of the unit tests, but will unblock future
diagnostic improvements.
* On suggestions that include deletions, use a diff inspired output format
* When suggesting addition, use `+` as underline
* Color highlight modified span
If a symbol name can only be imported from one place for a type, and
as long as it was not glob-imported anywhere in the current crate, we
can trim its printed path and print only the name.
This has wide implications on error messages with types, for example,
shortening `std::vec::Vec` to just `Vec`, as long as there is no other
`Vec` importable anywhere.
This adds a new '-Z trim-diagnostic-paths=false' option to control this
feature.
On the good path, with no diagnosis printed, we should try to avoid
issuing this query, so we need to prevent trimmed_def_paths query on
several cases.
This change also relies on a previous commit that differentiates
between `Debug` and `Display` on various rustc types, where the latter
is trimmed and presented to the user and the former is not.
In most places, we use a span when emitting `expected...found` errors.
However, there were a couple of places where we didn't use any span,
resulting in hard-to-interpret error messages.
This commit attaches the relevant span to these notes, and additionally
switches over to using `note_expected_found` instead of manually
formatting the message
Add outlives suggestions for some lifetime errors
This PR implements suggestion diagnostics for some lifetime mismatch errors. When the borrow checker finds that some lifetime 'a doesn't outlive some other lifetime 'b that it should outlive, then in addition to the current lifetime error, we also emit a suggestion for how to fix the problem by adding a bound:
- If a and b are normal named regions, suggest to add the bound `'a: 'b`
- If b is static, suggest to replace a with static
- If b also needs to outlive a, they must be the same, so suggest unifying them
We start with a simpler implementation that avoids diagnostic regression or implementation complexity:
- We only makes suggestions for lifetimes the user can already name (eg not closure regions or elided regions)
- For now, we only emit a help note, not an actually suggestion because it is significantly easier.
Finally, there is one hack: it seems that implicit regions in async fn are given the name '_ incorrectly. To avoid suggesting '_: 'x, we simply filter out such lifetimes by name.
For more info, see this internals thread:
https://internals.rust-lang.org/t/mechanical-suggestions-for-some-borrow-checker-errors/9049/3
TL;DR Make suggestions to add a `where 'a: 'b` constraint for some lifetime errors. Details are in the paper linked from the internals thread above.
r? @estebank
TODO
- [x] Clean up code
- [x] Only make idiomatic suggestions
- [x] don't suggest naming `&'a self`
- [x] rather than `'a: 'static`, suggest replacing `'a` with `'static`
- [x] rather than `'a: 'b, 'b: 'a`, suggest replacing `'a` with `'b` or vice versa
- [x] Performance (maybe need a perf run when this is closer to the finish line?)
- perf run was clean...
- EDIT: perf run seems to only check non-error performance... How do we check that error performance didn't regress?
- [x] Needs ui tests
- [x] Integrate the `help` message into the main lifetime `error`
Currently the default is "inherited" from context, so e.g. `&impl
Foo<Item = dyn Bar>` would default to `&'x impl Foo<Item = dyn Bar +
'x>`, but this triggers an ICE and is not very consistent.
This patch doesn't implement what I expect would be the correct
semantics, because those are likely too complex. Instead, it handles
what I'd expect to be the common case -- where the trait has no
lifetime parameters.
This commit updates the test output for the updated NLL compare mode
that uses `-Z borrowck=migrate` rather than `-Z borrowck=mir`. The
previous commit changes `compiletest` and this commit only updates
`.nll.stderr` files.
We used to apply it repeatedly as we went, relying on the current
value of the `region_bound_pairs_accum` vector. But now we save those
values into a map, so we can just process all the registered region
obligations at the end.