region errors: suggest new signature

661f3e9
Opened by Niko Matsakis at 2023-08-03 16:59:33

In some cases, we can suggest a new signature where the user introduces a new named lifetime. This is a bit tricky to figure out how to format the suggestion. It would get mildly easier with https://github.com/rust-lang/rfcs/pull/2115.

struct Ref<'a> { x: &'a u32 }

fn foo<T>(mut x: Vec<Ref<T>>, data: u32, y: Ref<T>)  {
    x.push(y);
}

The old code used to produce a modified form of the HIR to format the suggestion. I'd prefer not to do that. I was thinking we could probably do something simpler where we just emit the "new parts" of the signature, maybe like this?

hint: consider changing the signature as shown:
  | fn foo<'a, ...>(mut x: Vec<Ref<'a, T>>, ..., y: Ref<'a, T>)

Idea would be to do something like this:

  • Find name for a fresh lifetime that is not in scope (e.g., '``a)
  • Emit fn
  • Emit name of function (foo)
  • If the function has generic parameters already:
    • Emit <, fresh lifetime, , >
  • Else:
    • Emit <, fresh lifetime, >
  • Emit (
  • Emit if needed
  • Emit parameter name 1 and type (with fresh lifetime substituted)
  • Emit if needed
  • Emit parameter name 2 and type (with fresh lifetime substituted)
  • Emit if needed
  • Emit )

Not sure if this is a good plan. Might be best to wait until the https://github.com/rust-lang/rfcs/pull/2115 is settled, since that would permit us to make a suggestion where we just add a fresh named lifetime, and we don't have to add <'a> or anything.

  1. Current output:

    error[[E0107]](https://doc.rust-lang.org/stable/error_codes/E0107.html): struct takes 0 generic arguments but 1 generic argument was supplied
     --> src/lib.rs:3:22
      |
    3 | fn foo<T>(mut x: Vec<Ref<T>>, data: u32, y: Ref<T>)  {
      |                      ^^^ - help: remove this generic argument
      |                      |
      |                      expected 0 generic arguments
      |
    note: struct defined here, with 0 generic parameters
     --> src/lib.rs:1:8
      |
    1 | struct Ref<'a> { x: &'a u32 }
      |        ^^^
    
    error[[E0107]](https://doc.rust-lang.org/stable/error_codes/E0107.html): struct takes 0 generic arguments but 1 generic argument was supplied
     --> src/lib.rs:3:45
      |
    3 | fn foo<T>(mut x: Vec<Ref<T>>, data: u32, y: Ref<T>)  {
      |                                             ^^^ - help: remove this generic argument
      |                                             |
      |                                             expected 0 generic arguments
      |
    note: struct defined here, with 0 generic parameters
     --> src/lib.rs:1:8
      |
    1 | struct Ref<'a> { x: &'a u32 }
      |        ^^^
    
    error: lifetime may not live long enough
     --> src/lib.rs:4:5
      |
    3 | fn foo<T>(mut x: Vec<Ref>, data: u32, y: Ref)  {
      |           -----                       - has type `Ref<'1>`
      |           |
      |           has type `Vec<Ref<'2>>`
    4 |     x.push(y);
      |     ^^^^^^^^^ argument requires that `'1` must outlive `'2`
    

    Esteban Kuber at 2023-08-03 16:59:33