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

Confusing lifetime error: expected (&Location<'_>,), found (&Location<'_>,) #79033

Open
camelid opened this issue Nov 13, 2020 · 7 comments
Open
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-lifetimes Area: lifetime related D-confusing Diagnostics: Confusing error or lint that should be reworked. P-medium Medium priority regression-from-stable-to-stable Performance or correctness regression from one stable version to another. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@camelid
Copy link
Member

camelid commented Nov 13, 2020

For one, I'm not sure why this isn't working since Location is Copy, but you can fix this by just storing self.start.line and self.end.line in locals and adding move before the closure. One of the weird things about this error is it says

expected (&Location<'_>,), found (&Location<'_>,)

but those are the same! Also, why are they 1-tuples? The error is a bit different on stable, the message I showed is on nightly:

expected &Location<'_>, found &Location<'_>


Code

#[derive(Debug, Clone, Copy)]
pub struct Location<'a> {
    pub filename: &'a str,
    pub start: LocationHalf,
    pub end: LocationHalf,
}

#[derive(Debug, Clone, Copy)]
pub struct LocationHalf {
    pub line: u32,
    pub column: u32,
}

impl Location<'_> {
    /// Returns an iterator over the line numbers of this location.
    pub fn line_numbers(self) -> impl Iterator<Item = u32> {
        self.start.line..=self.end.line
    }

    /// Returns an iterator over the line numbers and lines of this location.
    pub fn lines<'a>(self, source: &'a str) -> impl Iterator<Item = (u32, &'a str)> {
        let lines = source.split('\n');
        lines.enumerate().filter_map(|(i, line)| {
            if self.start.line as usize <= i && i <= self.end.line as usize {
                Some((i as u32 + 1, line))
            } else {
                None
            }
        })
    }
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
  --> src/lib.rs:23:38
   |
23 |           lines.enumerate().filter_map(|(i, line)| {
   |  ______________________________________^
24 | |             if self.start.line as usize <= i && i <= self.end.line as usize {
25 | |                 Some((i as u32 + 1, line))
26 | |             } else {
27 | |                 None
28 | |             }
29 | |         })
   | |_________^
   |
note: first, the lifetime cannot outlive the lifetime `'_` as defined on the impl at 14:15...
  --> src/lib.rs:14:15
   |
14 | impl Location<'_> {
   |               ^^
note: ...so that the types are compatible
  --> src/lib.rs:23:38
   |
23 |           lines.enumerate().filter_map(|(i, line)| {
   |  ______________________________________^
24 | |             if self.start.line as usize <= i && i <= self.end.line as usize {
25 | |                 Some((i as u32 + 1, line))
26 | |             } else {
27 | |                 None
28 | |             }
29 | |         })
   | |_________^
   = note: expected `(&Location<'_>,)`
              found `(&Location<'_>,)`
note: but, the lifetime must be valid for the lifetime `'a` as defined on the method body at 21:18...
  --> src/lib.rs:21:18
   |
21 |     pub fn lines<'a>(self, source: &'a str) -> impl Iterator<Item = (u32, &'a str)> {
   |                  ^^
note: ...so that return value is valid for the call
  --> src/lib.rs:21:48
   |
21 |     pub fn lines<'a>(self, source: &'a str) -> impl Iterator<Item = (u32, &'a str)> {
   |                                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0495`.
error: could not compile `playground`

To learn more, run the command again with --verbose.

@camelid camelid added A-lifetimes Area: lifetime related regression-from-stable-to-nightly Performance or correctness regression from stable to nightly. D-confusing Diagnostics: Confusing error or lint that should be reworked. labels Nov 13, 2020
@rustbot rustbot added the I-prioritize Issue: Indicates that prioritization has been requested for this issue. label Nov 13, 2020
@camelid
Copy link
Member Author

camelid commented Nov 13, 2020

I marked this as a regression since the error has gotten worse since stable and beta.

@camelid camelid added A-diagnostics Area: Messages for errors, warnings, and lints T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Nov 13, 2020
@jyn514
Copy link
Member

jyn514 commented Nov 13, 2020

This looks like another duplicate of #41078.

@camelid
Copy link
Member Author

camelid commented Nov 13, 2020

Adding type annotations to the closure doesn't fix it though:

#[derive(Debug, Clone, Copy)]
pub struct Location<'a> {
    pub filename: &'a str,
    pub start: LocationHalf,
    pub end: LocationHalf,
}

#[derive(Debug, Clone, Copy)]
pub struct LocationHalf {
    pub line: u32,
    pub column: u32,
}

impl Location<'_> {
    /// Returns an iterator over the line numbers of this location.
    pub fn line_numbers(self) -> impl Iterator<Item = u32> {
        self.start.line..=self.end.line
    }

    /// Returns an iterator over the line numbers and lines of this location.
    pub fn lines<'a>(self, source: &'a str) -> impl Iterator<Item = (u32, &'a str)> {
        let lines = source.split('\n');
        lines.enumerate().filter_map(|(i, line): (usize, &'a str)| {
            if self.start.line as usize <= i && i <= self.end.line as usize {
                Some((i as u32 + 1, line))
            } else {
                None
            }
        })
    }
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
  --> src/lib.rs:23:38
   |
23 |           lines.enumerate().filter_map(|(i, line): (usize, &'a str)| {
   |  ______________________________________^
24 | |             if self.start.line as usize <= i && i <= self.end.line as usize {
25 | |                 Some((i as u32 + 1, line))
26 | |             } else {
27 | |                 None
28 | |             }
29 | |         })
   | |_________^
   |
note: first, the lifetime cannot outlive the lifetime `'_` as defined on the impl at 14:15...
  --> src/lib.rs:14:15
   |
14 | impl Location<'_> {
   |               ^^
note: ...so that the types are compatible
  --> src/lib.rs:23:38
   |
23 |           lines.enumerate().filter_map(|(i, line): (usize, &'a str)| {
   |  ______________________________________^
24 | |             if self.start.line as usize <= i && i <= self.end.line as usize {
25 | |                 Some((i as u32 + 1, line))
26 | |             } else {
27 | |                 None
28 | |             }
29 | |         })
   | |_________^
   = note: expected `(&Location<'_>,)`
              found `(&Location<'_>,)`
note: but, the lifetime must be valid for the lifetime `'a` as defined on the method body at 21:18...
  --> src/lib.rs:21:18
   |
21 |     pub fn lines<'a>(self, source: &'a str) -> impl Iterator<Item = (u32, &'a str)> {
   |                  ^^
note: ...so that return value is valid for the call
  --> src/lib.rs:21:48
   |
21 |     pub fn lines<'a>(self, source: &'a str) -> impl Iterator<Item = (u32, &'a str)> {
   |                                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0495`.
error: could not compile `playground`

To learn more, run the command again with --verbose.

@camelid
Copy link
Member Author

camelid commented Nov 13, 2020

Also, notice that the error note shows tuples on nightly but not stable – that seems like a bug. And, why does the error say:

note: first, the lifetime cannot outlive the lifetime `'_` as defined on the impl at 14:15...
  --> src/lib.rs:14:15
   |
14 | impl Location<'_> {
   |               ^^
note: ...so that the types are compatible
  --> src/lib.rs:23:38
   |
23 |           lines.enumerate().filter_map(|(i, line): (usize, &'a str)| {
   |  ______________________________________^
24 | |             if self.start.line as usize <= i && i <= self.end.line as usize {
25 | |                 Some((i as u32 + 1, line))
26 | |             } else {
27 | |                 None
28 | |             }
29 | |         })
   | |_________^
   = note: expected `(&Location<'_>,)`
              found `(&Location<'_>,)`

I don't understand why it must match the Location's lifetime and also why adding move before the closure doesn't fix the problem.

@camelid camelid added the D-incorrect Diagnostics: A diagnostic that is giving misleading or incorrect information. label Nov 13, 2020
@jyn514
Copy link
Member

jyn514 commented Nov 13, 2020

Here is a fixed version: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=3d9156ed9de67e4bf402f54243f5f3e8
Here is a fixed version that still captures self in the closure (although that's rarely what you want): https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=8dd9c0596d4399be5bbdacb0629d7189

So the error is correct, it's just confusing.

@jyn514 jyn514 removed the D-incorrect Diagnostics: A diagnostic that is giving misleading or incorrect information. label Nov 13, 2020
@spastorino
Copy link
Member

spastorino commented Nov 18, 2020

Assigning P-medium as discussed as part of the Prioritization Working Group procedure and removing I-prioritize.

@spastorino spastorino added P-medium Medium priority and removed I-prioritize Issue: Indicates that prioritization has been requested for this issue. labels Nov 18, 2020
@camelid
Copy link
Member Author

camelid commented Nov 20, 2020

I still don't really understand why this code doesn't work, but the confusing error should be fixed by #73521.

@Mark-Simulacrum Mark-Simulacrum added regression-from-stable-to-stable Performance or correctness regression from one stable version to another. and removed regression-from-stable-to-nightly Performance or correctness regression from stable to nightly. labels Jan 21, 2021
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 A-lifetimes Area: lifetime related D-confusing Diagnostics: Confusing error or lint that should be reworked. P-medium Medium priority regression-from-stable-to-stable Performance or correctness regression from one stable version to another. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

5 participants