Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[NLL] Record more infomation on free region constraints in typeck #54262

Merged
merged 5 commits into from Sep 23, 2018

Conversation

matthewjasper
Copy link
Contributor

Changes:

  • Makes the span of the MIR return place point to the return type
  • Don't try to use a path to a type alias as a path to the adt it aliases (fixes an ICE)
  • Don't claim that self is declared outside of the function. see this test
  • Remove boring/interesting distinction and instead add a ConstraintCategory to the constraint.
  • Add categories for implicit Sized and Copy requirements, for closure bounds, for user type annotations and impl Trait.
  • Don't use the span of the first statement for Locations::All bounds (even if it happens to work on the tests we have)

Future work:

  • Fine tuning the heuristic used to choose the place the report the error.
  • Reporting multiple places (behind a flag)
  • Better closure bounds reporting. This probably requires some discussion.

r? @nikomatsakis

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Sep 15, 2018
@matthewjasper matthewjasper added the A-NLL Area: Non Lexical Lifetimes (NLL) label Sep 15, 2018
@bors
Copy link
Contributor

bors commented Sep 18, 2018

☔ The latest upstream changes (presumably #53900) made this pull request unmergeable. Please resolve the merge conflicts.

a: Ty<'tcx>,
b: Ty<'tcx>,
locations: Locations,
category: ConstraintCategory,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, I did not want to do it this way — but I'm trying to remember why and coming up empty. Seems ok.

I'm wondering if it makes sense to keep both locations and category as distinct things. Perhaps so: in particular, locations (once we transition to polonius) will be relevant to whether or not this is an error, whereas category is not.

| ^^^^^^^^^^^ assignment requires that `'b` must outlive `'a`
...
LL | (a, b) //[krisskross]~ ERROR 55:5: 55:6: lifetime mismatch [E0623]
| ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting example. I feel like this is a good case where I'd prefer to see more than one highlight.

Or, even better, if we could highlight a and not the entire tuple. I think this would be possible: we could probably detect if we are returning an aggregate and see if we can trace back to one of the inputs into the aggregate. This is particularly easy in tuples.

That said, another route that might be better (or just complementary) is to highlight more than one location. In this case, I think it'd be nice to highlight the bar(foo, y) point as well, basically saying "data gets the lifetime 'a from here". Anyway, I'm noting this down for further iteration.

|
LL | x
| ^
LL | fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this feels like a regression, no?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess actually it's another case of "it'd be nice to highlight more spots"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The highlighted span is the span of the first statement, it just happens to be the right span in this case.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lol ok

|
LL | x
| ^
LL | fn foo<T>(x: T) -> impl Any + 'static {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

another case where highlight the return type feels not quite right

the core problem here is that, with impl Trait in particular, it's useful to highlight the return type.

I wonder if we could add a note like this:

error[E0310]: the parameter type `T` may not live long enough
  --> $DIR/type_parameters_captured.rs:17:20
   |
LL | fn foo<T>(x: T) -> impl Any + 'static {
   |                    ^^^^^^^^^^^^^^^^^^
LL |     x
   |    - the `impl Trait` is inferred to have the type `T`
LL | }
   |
= help: consider adding an explicit lifetime bound `T: 'static`...

The idea would be to find the span(s) of where the return slot is assigned and use those, and just show the underlying type.

| _________________________________________________________________^
LL | | x //~ ERROR E0312
LL | | }));
| |_____^ closure body requires that `'x` must outlive `'static`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this case would be addressed by @davidtwco's PR -- anyway, feels like an improvement in this PR, if not optimal.

@@ -6,7 +6,7 @@ LL | fn foo(mut x: Ref, y: &u32) {
| |
| has type `Ref<'_, '2>`
LL | x.b = y; //~ ERROR lifetime mismatch
| ^^^^^^^ requires that `'1` must outlive `'2`
| ^^^^^^^ assignment requires that `'1` must outlive `'2`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: is this an improvement? It seems like it's sort of obvious that it's an assignment, not sure if it helps for us to say so?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe if we said something better, like "data with lifetime '1 is stored into a location with lifetime '2 here"? that doesn't quite sound right either.

...
LL | let _x = *s; //~ ERROR
| ^^ `s` escapes the function body here
| ^^ proving this value is `Sized` requires that `'a` must outlive `'static`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice

| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: consider adding an explicit lifetime bound `T: ReFree(DefId(0/0:8 ~ projection_one_region_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:16), 'a))`...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ closure body requires that `'b` must outlive `'a`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, pulling out the constraint category into typeck might mean that we can package it up with the ClosureRegionRequirements, as well. Have to think a bit about that. This might enable us to give finer-grained reports here.

LL | fn i<'a, T, U>(v: Box<A<U>+'a>) -> Box<X+'static> {
| -- lifetime `'a` defined here
LL | box B(&*v) as Box<X> //~ ERROR cannot infer
| ^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in these cases, it'd be really nice if we could tie this a bit harder to the return type. good follow-up.

@nikomatsakis
Copy link
Contributor

r=me post rebase

The MIR/NLL type checker is in a much better position to classify
constraints and already has to classify into boring and interesting.
Adds spans to Locations::All for error reporting
Adds more constraint categories
@nikomatsakis
Copy link
Contributor

@bors r+

@bors
Copy link
Contributor

bors commented Sep 20, 2018

📌 Commit bd0895d has been approved by nikomatsakis

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Sep 20, 2018
@bors
Copy link
Contributor

bors commented Sep 23, 2018

⌛ Testing commit bd0895d with merge 576b640...

bors added a commit that referenced this pull request Sep 23, 2018
[NLL] Record more infomation on free region constraints in typeck

Changes:

* Makes the span of the MIR return place point to the return type
* Don't try to use a path to a type alias as a path to the adt it aliases (fixes an ICE)
* Don't claim that `self` is declared outside of the function. [see this test](f2995d5#diff-0c9e6b1b204f42129b481df9ce459d44)
* Remove boring/interesting distinction and instead add a `ConstraintCategory` to the constraint.
* Add categories for implicit `Sized` and `Copy` requirements, for closure bounds, for user type annotations and `impl Trait`.
* Don't use the span of the first statement for Locations::All bounds (even if it happens to work on the tests we have)

Future work:

* Fine tuning the heuristic used to choose the place the report the error.
* Reporting multiple places (behind a flag)
* Better closure bounds reporting. This probably requires some discussion.

r? @nikomatsakis
@bors
Copy link
Contributor

bors commented Sep 23, 2018

☀️ Test successful - status-appveyor, status-travis
Approved by: nikomatsakis
Pushing 576b640 to master...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-NLL Area: Non Lexical Lifetimes (NLL) S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants