Skip to content

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

Open
@camelid

Description

@camelid
Member

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.

Activity

added
A-lifetimesArea: Lifetimes / regions
D-confusingDiagnostics: Confusing error or lint that should be reworked.
on Nov 13, 2020
added
I-prioritizeIssue: Indicates that prioritization has been requested for this issue.
on Nov 13, 2020
camelid

camelid commented on Nov 13, 2020

@camelid
MemberAuthor

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

added
A-diagnosticsArea: Messages for errors, warnings, and lints
T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
on Nov 13, 2020
jyn514

jyn514 commented on Nov 13, 2020

@jyn514
Member

This looks like another duplicate of #41078.

camelid

camelid commented on Nov 13, 2020

@camelid
MemberAuthor

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

camelid commented on Nov 13, 2020

@camelid
MemberAuthor

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.

added
D-incorrectDiagnostics: A diagnostic that is giving misleading or incorrect information.
on Nov 13, 2020
jyn514

jyn514 commented on Nov 13, 2020

@jyn514
Member

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.

removed
D-incorrectDiagnostics: A diagnostic that is giving misleading or incorrect information.
on Nov 13, 2020
spastorino

spastorino commented on Nov 18, 2020

@spastorino
Member

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

removed
I-prioritizeIssue: Indicates that prioritization has been requested for this issue.
on Nov 18, 2020

4 remaining items

Loading
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 lintsA-lifetimesArea: Lifetimes / regionsD-confusingDiagnostics: Confusing error or lint that should be reworked.P-mediumMedium priorityT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.regression-from-stable-to-stablePerformance or correctness regression from one stable version to another.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @spastorino@Mark-Simulacrum@jyn514@camelid@rustbot

        Issue actions

          Confusing lifetime error: expected `(&Location<'_>,)`, found `(&Location<'_>,)` · Issue #79033 · rust-lang/rust