properly handle anonymous regions appearing in return type- named-anon conflicts

940acaa
Opened by Gauri Kholkar at 2023-06-30 15:44:19

These cases, going by the way #42669 for one named and other anonymous lifetime parameter , the error message generated would suggest consider changing type of self to &'a i32. In the first case, this is fine but the second case, with self.field not being the return value, the message is wrong and should only suggest changing the return type. We need to differentiate both the cases and fix the error message for the second case.

fn foo<'a>(&self, x: &'a i32) -> &i32 {
 // Preferred message:
 //     fn foo<'a>(&self, x: &'a i32) -> &i32 {
 //                 -----                 ---- consider changing to `&'a i32`
 //                 |
 //                 consider changing to `&'a self`
    if true { &self.field } else { x }
  }
fn foo<'a>(&self, x: &'a i32) -> &i32 {
//       preferred error
//       fn foo<'a>(&self, x: &'a i32) -> &i32 {             
//                                         ---- consider changing to `&'a i32`
    x

// error[E0611]: explicit lifetime required in the type of `self`
//    |
// 33 |     fn foo<'a>(&self, x: &'a i32) -> &i32 {
//    |                 ^^^^^ consider changing the type of `self` to `&'a Foo`
// 34 |         //                             
// 35 |         x
//    |         - lifetime `'a` required
  }

cc @nikomatsakis

  1. So the problem here is that, without examining the region graph closely, we can't tell the difference between these two cases. This is non-trivial to solve: I have to say that when I took a look at the region inference graphs for these two cases, I failed to see any obvious rules we could use to distinguish them. We may have to add additional refinement into the "causes" and so forth to figure this out.

    Niko Matsakis at 2017-07-17 13:03:49

  2. I had a thought about possibly changing the error message to avoid doing complex analysis. Maybe instead of suggesting to the user what change they ought to make (which would require analysis), we might do a better job just telling them what is needed. So the two cases would look like:

    fn foo<'a>(&self, x: &'a i32) -> &i32 {
        //               -------     ---- these references must have the same lifetime
        x
    //  ^ data from `x` is returned here
    }
    
    fn foo<'a>(&self, x: &'a i32) -> &i32 {
        //               -------     ---- these references must have the same lifetime
        if true { &self.field } else { x }
        //                             ^ data from `x` is returned here
    }
    

    The second case is, I guess, non-ideal, in that it would be nicer if we could underline all three references.

    Niko Matsakis at 2017-07-24 04:08:21

  3. working on this now

    Gauri Kholkar at 2017-08-21 16:36:42

  4. Seems like we could use some mentoring instructions here!

    Niko Matsakis at 2017-09-22 15:10:18

  5. @gaurikholkar I'm not sure, did we ever land code fixing this?

    Niko Matsakis at 2017-09-22 15:10:32

  6. @nikomatsakis for now, #44124 handles them all

    Gauri Kholkar at 2017-09-29 15:10:52

  7. @gaurikholkar we can close this ticket now, right?

    Esteban Kuber at 2017-11-04 01:15:49

  8. For Case 1,

    5 | fn foo<'a>(&self, x: &'a i32) -> &i32 
      |                      -------     ----
      |                      |
      |                      this parameter and the return type are declared with different lifetimes...
    6 |         x
      |         ^ ...but data from `x` is returned here
    

    Case 2

    5 | fn foo<'a>(&self, x: &'a i32) -> &i32 
      |                      -------     ----
      |                      |
      |                      this parameter and the return type are declared with different lifetimes...
    6 |         if true {x} else {&self}
      |                  ^ ...but data from `x` is returned here
    

    @nikomatsakis afaik, we were planning to further modify the error message. Should we open up a new issue for that? cc @estebank

    Gauri Kholkar at 2017-11-19 18:34:54

  9. Current output:

    error[E0623]: lifetime mismatch
      --> src/lib.rs:12:36
       |
    6  | fn foo<'a>(&self, x: &'a i32) -> &i32 {
       |                      -------     ----
       |                      |
       |                      this parameter and the return type are declared with different lifetimes...
    ...
    12 |     if true { &self.field } else { x }
       |                                    ^ ...but data from `x` is returned here
    
    error[E0623]: lifetime mismatch
      --> src/lib.rs:19:5
       |
    15 |   fn bar<'a>(&self, x: &'a i32) -> &i32 {
       |                        -------     ----
       |                        |
       |                        this parameter and the return type are declared with different lifetimes...
    ...
    19 |     x
       |     ^ ...but data from `x` is returned here
    

    Only missing thing would be to suggest changing the lifetimes.

    Esteban Kuber at 2019-10-15 18:14:22

  10. Current output:

    error: lifetime may not live long enough
      --> src/lib.rs:12:36
       |
    6  | fn foo<'a>(&self, x: &'a i32) -> &i32 {
       |        --  - let's call the lifetime of this reference `'1`
       |        |
       |        lifetime `'a` defined here
    ...
    12 |     if true { &self.field } else { x }
       |                                    ^ associated function was supposed to return data with lifetime `'1` but it is returning data with lifetime `'a`
    
    error: lifetime may not live long enough
      --> src/lib.rs:19:5
       |
    15 |   fn bar<'a>(&self, x: &'a i32) -> &i32 {
       |          --  - let's call the lifetime of this reference `'1`
       |          |
       |          lifetime `'a` defined here
    ...
    19 |     x
       |     ^ associated function was supposed to return data with lifetime `'1` but it is returning data with lifetime `'a`
    

    Esteban Kuber at 2022-12-28 00:06:54