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

Unhelpful error message for E0308 #44684

Closed
chordowl opened this issue Sep 18, 2017 · 2 comments
Closed

Unhelpful error message for E0308 #44684

chordowl opened this issue Sep 18, 2017 · 2 comments
Labels
A-diagnostics Area: Messages for errors, warnings, and lints C-enhancement Category: An issue proposing an enhancement or a PR with one. WG-diagnostics Working group: Diagnostics

Comments

@chordowl
Copy link
Contributor

chordowl commented Sep 18, 2017

When trying the following code (playground), the result error message is incredibly unhelpful and confusing:

Code sample
#[derive(Clone)]
enum Foo<'a> {
    Bar(&'a str),
}

impl<'a> Foo<'a> {
    fn bar(&self, other: Foo) -> Foo {
        match *self {
            Foo::Bar(s) => {
                if s == "test" {
                    other
                } else {
                    self.clone()
                }
            }
        }
    }
}
Error message
error[E0308]: mismatched types
  --> src/main.rs:11:21
   |
11 |                     other
   |                     ^^^^^ lifetime mismatch
   |
   = note: expected type `Foo<'_>`
              found type `Foo<'_>`
note: the anonymous lifetime #2 defined on the method body at 7:5...
  --> src/main.rs:7:5
   |
7  | /     fn bar(&self, other: Foo) -> Foo {
8  | |         match *self {
9  | |             Foo::Bar(s) => {
10 | |                 if s == "test" {
...  |
16 | |         }
17 | |     }
   | |_____^
note: ...does not necessarily outlive the anonymous lifetime #1 defined on the method body at 7:5
  --> src/main.rs:7:5
   |
7  | /     fn bar(&self, other: Foo) -> Foo {
8  | |         match *self {
9  | |             Foo::Bar(s) => {
10 | |                 if s == "test" {
...  |
16 | |         }
17 | |     }
   | |_____^

The expected and found type are both displayed as Foo<'_>, although I guess this is expected as the two '_ refer to different anonymous lifetimes. But then, it doesn't help that the spans for those two anonymous lifetimes are (visually) identical.

@aidanhs aidanhs added the C-enhancement Category: An issue proposing an enhancement or a PR with one. label Sep 19, 2017
@QuietMisdreavus QuietMisdreavus added the A-diagnostics Area: Messages for errors, warnings, and lints label Sep 21, 2017
@estebank
Copy link
Contributor

estebank commented Sep 21, 2017

The presented code is equivalent to

#[derive(Clone)]
enum Foo<'a> {
    Bar(&'a str),
}

impl<'a> Foo<'a> {
    fn bar(&self, other: Foo) -> Foo<'a> {
        match *self {
            Foo::Bar(s) => {
                if s == "test" {
                    other
                } else {
                    self.clone()
                }
            }
        }
    }
}

which fails with a similar error, but slightly clearer:

error[E0308]: mismatched types
  --> src/main.rs:11:21
   |
11 |                     other
   |                     ^^^^^ lifetime mismatch
   |
   = note: expected type `Foo<'a>`
              found type `Foo<'_>`
note: the anonymous lifetime #2 defined on the method body at 7:5...
  --> src/main.rs:7:5
   |
7  | /     fn bar(&self, other: Foo) -> Foo<'a> {
8  | |         match *self {
9  | |             Foo::Bar(s) => {
10 | |                 if s == "test" {
...  |
16 | |         }
17 | |     }
   | |_____^
note: ...does not necessarily outlive the lifetime 'a as defined on the impl at 6:1
  --> src/main.rs:6:1
   |
6  | / impl<'a> Foo<'a> {
7  | |     fn bar(&self, other: Foo) -> Foo<'a> {
8  | |         match *self {
9  | |             Foo::Bar(s) => {
...  |
17 | |     }
18 | | }
   | |_^

The proper code is

#[derive(Clone)]
enum Foo<'a> {
    Bar(&'a str),
}

impl<'a> Foo<'a> {
    fn bar(&self, other: Foo<'a>) -> Foo<'a> {
                         // ^^^^ note the explicit lifetime here
        match *self {
            Foo::Bar(s) => {
                if s == "test" {
                    other
                } else {
                    self.clone()
                }
            }
        }
    }
}

Once you specify a lifetime for other: Foo<'a> it works even if the return type is -> Foo { with the implicit lifetime.

We do need to improve the output of this error message. I think this case falls under the same situation as #42703. Once the PR fixing that lands, I'll verify wether it covers this case.

@estebank
Copy link
Contributor

estebank commented Oct 5, 2017

Current output for the original code is much improved:

error[E0623]: lifetime mismatch
  --> src/main.rs:11:21
   |
7  |     fn bar(&self, other: Foo) -> Foo {
   |                          ---     ---
   |                          |
   |                          this parameter and the return type are declared with different lifetimes...
...
11 |                     other
   |                     ^^^^^ ...but data from `other` is returned here

A suggestion to specify a lifetime for the argument is still missing (as the PR handles borrows, not ADTs with borrows), and gives the old diagnostic when the method has the following signature:

fn bar(&self, other: Foo) -> Foo<'a>

That being said, at least in this case it makes a bit more sense, as there's a reference to 'a and '_ which points in the right direction (it still needs improvement):

error[E0308]: mismatched types
  --> src/main.rs:11:21
   |
11 |                     other
   |                     ^^^^^ lifetime mismatch
   |
   = note: expected type `Foo<'a>`
              found type `Foo<'_>`
note: the anonymous lifetime #2 defined on the method body at 7:5...
  --> src/main.rs:7:5
   |
7  | /     fn bar(&self, other: Foo) -> Foo<'a> {
8  | |         match *self {
9  | |             Foo::Bar(s) => {
10 | |                 if s == "test" {
...  |
16 | |         }
17 | |     }
   | |_____^
note: ...does not necessarily outlive the lifetime 'a as defined on the impl at 6:1
  --> src/main.rs:6:1
   |
6  | / impl<'a> Foo<'a> {
7  | |     fn bar(&self, other: Foo) -> Foo<'a> {
8  | |         match *self {
9  | |             Foo::Bar(s) => {
...  |
17 | |     }
18 | | }
   | |_^

@estebank estebank added E-needs-mentor WG-diagnostics Working group: Diagnostics labels Oct 5, 2017
kennytm added a commit to kennytm/rust that referenced this issue Nov 7, 2017
Handle anon lifetime arg being returned with named lifetime return type

When there's a lifetime mismatch between an argument with an anonymous
lifetime being returned in a method with a return type that has a named
lifetime, show specialized lifetime error pointing at argument with a
hint to give it an explicit lifetime matching the return type.

```
error[E0621]: explicit lifetime required in the type of `other`
  --> file2.rs:21:21
   |
17 |     fn bar(&self, other: Foo) -> Foo<'a> {
   |                   ----- consider changing the type of `other` to `Foo<'a>`
...
21 |                     other
   |                     ^^^^^ lifetime `'a` required
```

Follow up to rust-lang#44124 and rust-lang#42669. Fix rust-lang#44684.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-diagnostics Area: Messages for errors, warnings, and lints C-enhancement Category: An issue proposing an enhancement or a PR with one. WG-diagnostics Working group: Diagnostics
Projects
None yet
Development

No branches or pull requests

4 participants