Skip to content

Suggestion for single_use_lifetimes suggests code that fails to compile #117965

Closed
@jhpratt

Description

@jhpratt

playground

#![deny(single_use_lifetimes)]

pub enum Data<'a> {
    Borrowed(&'a str),
    Owned(String),
}

impl<'a> Data<'a> {
    pub fn get<'b: 'a>(&'b self) -> &'a str {
        match &self {
            Self::Borrowed(val) => val,
            Self::Owned(val) => &val,
        }
    }
}

This code, as expected, triggers the lint. This is the compiler output:

error: lifetime parameter `'b` only used once
 --> src/lib.rs:9:16
  |
9 |     pub fn get<'b: 'a>(&'b self) -> &'a str {
  |                ^^       -- ...is used only here
  |                |
  |                this lifetime...
  |
note: the lint level is defined here
 --> src/lib.rs:1:9
  |
1 | #![deny(single_use_lifetimes)]
  |         ^^^^^^^^^^^^^^^^^^^^
help: elide the single-use lifetime
  |
9 -     pub fn get<'b: 'a>(&'b self) -> &'a str {
9 +     pub fn get(&self) -> &'a str {
  |

Applying the suggested change, we then get a lifetime error.

error: lifetime may not live long enough
  --> src/lib.rs:10:9
   |
8  |   impl<'a> Data<'a> {
   |        -- lifetime `'a` defined here
9  |       pub fn get(&self) -> &'a str {
   |                  - let's call the lifetime of this reference `'1`
10 | /         match &self {
11 | |             Self::Borrowed(val) => val,
12 | |             Self::Owned(val) => &val,
13 | |         }
   | |_________^ method was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1`

In this specific instance, &'a str must also be changed to &str. That'll then trigger the lint on impl<'a> Data<'a>, with no ensuing issues.

I have not checked this, but I my suspicion is any place where a lifetime bound is also present in the return type (or possibly even a parameter) will result in a similar failure to compile the suggested code. Figuring out which lifetimes to suggest removal of in other parts of the function signature probably isn't straightforward.

This example is not theoretical, unfortunately. I ran into this in real-world code and it caused me quite a bit of time to figure out. The example is the minimal reproduction of the bad suggestion.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-diagnosticsArea: Messages for errors, warnings, and lintsA-lintsArea: Lints (warnings about flaws in source code) such as unused_mut.C-bugCategory: This is a bug.D-invalid-suggestionDiagnostics: A structured suggestion resulting in incorrect code.F-lint-single_use_lifetimes`single_use_lifetimes` lintT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.WG-diagnosticsWorking group: Diagnostics

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions