Skip to content

Unhelpful error message for E0308 #44684

Closed
@chordowl

Description

@chordowl
Contributor

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.

Activity

added
C-enhancementCategory: An issue proposing an enhancement or a PR with one.
on Sep 19, 2017
estebank

estebank commented on Sep 21, 2017

@estebank
Contributor

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

estebank commented on Oct 5, 2017

@estebank
Contributor

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 | | }
   | |_^
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-diagnosticsArea: Messages for errors, warnings, and lintsC-enhancementCategory: An issue proposing an enhancement or a PR with one.WG-diagnosticsWorking group: Diagnostics

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @aidanhs@estebank@chordowl@QuietMisdreavus

        Issue actions

          Unhelpful error message for E0308 · Issue #44684 · rust-lang/rust