mozilla/rust — pull request #12238 by ktt3ja (2014-02-13 08:55:07+00:00)
Title: Suggest explicit lifetime parameter

This is a WiP. For the following code snippet:

```rust
struct Foo { bar: int }
fn foo(x: &Foo) -> &int {
&x.bar
}
```

This PR generates the following error message:

```rust
test.rs:3:5: 3:11 error: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
test.rs:3 &x.bar
^~~~~~
note: consider using an explicit lifetime parameter as shown:
fn foo<'a>(x: &'a Foo) -> &'a int
error: aborting due to previous error
```

I wanted to make the change self-contained, but because of that there are a few issues, so I would like to seek some feedback. My approach is as followed:

* For SubSupConflict `sub_r <= ... <= 'v <= ... <= sup_r`, check that `sub_r` and `sup_r` are both free lifetimes.
* Require that at least one of `sub_r` or `sup_r` has anonymous binding (since I use the anonymous number to count).
* Identify that they come from a function declaration and obtain the AST of that function declaration. (hence why it's rebased on top of eddby's PR)
* Since the compiler appears to identify the first anonymous binding of a function with the number 0 and increment each subsequent one by 1, I use the same strategy to identify where to insert/replace the lifetime in the AST.
* Use the Rust pretty printer to print the new function declaration.

Some issues it has are:
* I'm not sure if just checking that `sub_r` and `sup_r` are free region is enough. It may generate false positive.
* Since I use anonymous lifetime number to find where to insert/change the lifetime, it doesn't handle the case where both `sub_r` and `sup_r` have named binding. For example, it doesn't generate a nice note for the following function:
``` rust
fn foo<'a, 'b>(x: &'a Foo) -> &'b int {
&x.bar
}
```
To fix this, I'm considering adding an extra field to `BrAnon` and `BrNamed` (or maybe just the latter) to hold the NodeId of where the lifetime came from.

* It doesn't handle the case where three or more lifetimes have to be the same correctly. For example,
```rust
fn foo(x: &Foo) -> (&int, &int) {
(&x.bar, &x.bar)
}
```
would generate
```rust
test.rs:3:6: 3:12 error: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
test.rs:3 (&x.bar, &x.bar)
^~~~~~
note: consider using an explicit lifetime parameter as shown:
fn foo<'a>(x: &'a Foo) -> (&'a int, &int)
test.rs:3:14: 3:20 error: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
test.rs:3 (&x.bar, &x.bar)
^~~~~~
note: consider using an explicit lifetime parameter as shown:
fn foo<'a>(x: &'a Foo) -> (&int, &'a int)
error: aborting due to 2 previous errors
```

To fix this, I'm guessing I would have to collect all the `SubSupConflict` at once before reporting them.

cc @nikomatsakis