Skip to content

Missing lifetimes needed in impl item don't have enough help for newcomer devs #135589

Open
@estebank

Description

If you write like

impl IntoIterator for &S {
    type Item = &T;
    type IntoIter = std::collections::btree_map::Values<i32, T>;
    
    fn into_iter(self) -> Self::IntoIter {
        todo!()
    }
}

you get the following errors

error: in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type
 --> src/main.rs:5:17
  |
5 |     type Item = &T;
  |                 ^ this lifetime must come from the implemented type

error[E0106]: missing lifetime specifier
 --> src/main.rs:6:56
  |
6 |     type IntoIter = std::collections::btree_map::Values<i32, T>;
  |                                                        ^ expected named lifetime parameter
  |
help: consider introducing a named lifetime parameter
  |
6 |     type IntoIter<'a> = std::collections::btree_map::Values<'a, i32, T>;
  |                  ++++                                       +++

ignoring the first one for now, if you follow the suggestion you get

error[E0195]: lifetime parameters or bounds on type `IntoIter` do not match the trait declaration
 --> src/main.rs:6:18
  |
6 |     type IntoIter<'a> = std::collections::btree_map::Values<'a, i32, T>;
  |                  ^^^^ lifetimes do not match type in trait

Both of these cases should instead mention likely adding the lifetime to the impl if either the trait or the self type have any lifetimes, named or anon. We should mention that the <'a> should be removed to match the def, and point at the def if local to modify it to add it to the trait.

If we don't add the <'a> to the type IntoIter, we get something closer to what we want:

error[E0261]: use of undeclared lifetime name `'a`
 --> src/main.rs:6:57
  |
6 |     type IntoIter = std::collections::btree_map::Values<'a, i32, T>;
  |                                                         ^^ undeclared lifetime
  |
help: consider introducing lifetime `'a` here
  |
6 |     type IntoIter<'a> = std::collections::btree_map::Values<'a, i32, T>;
  |                  ++++
help: consider introducing lifetime `'a` here
  |
4 | impl<'a> IntoIterator for &S {
  |     ++++

We shouldn't be suggesting modifying type IntoIter if we can know that the trait definition didn't have named lifetimes.

If we add impl<'a>, then we get a very terse output:

error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
 --> src/main.rs:4:6
  |
4 | impl<'a> IntoIterator for &S {
  |      ^^ unconstrained lifetime parameter

This should look at the trait and self type and see if there is any anon lifetime at play, and suggest using the named lifetime there. In this case, &'a S.

In all of these cases we still get:

error: in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type
 --> src/main.rs:5:17
  |
5 |     type Item = &T;
  |                 ^ this lifetime must come from the implemented type

When impl has lifetimes, the above should suggest using that lifetime.

Currently the documentation of E0261 mentions a similar enough case, but E0207 doesn't. We'd likely want to add a mention about lifetimes in the latter.

Inspired by mainmatter/100-exercises-to-learn-rust#245


  • on type NoLt = TypeMissingLt;, do not suggest type NoLt<'a> = TypeMisingLt<'a>; if the trait doesn't accept it
  • on type NoLt = TypeMissingLt;, suggest adding a lifetime to the impl if the trait or self type have anon lifetimes
  • on type NoLt<'a> = TypeMissingLt<'a>;, suggest removing the lifetime from the type if the impl has a named lifetime
  • on type NoLt = TypeMissingLt<'a>;, suggest adding 'a to the impl if the trait or self type have anon lifetimes
  • on impl<'a> IntoIterator for &S, suggest changing the self type to &'a S
  • on type NoLt = &T;, if impl has a lifetime suggest using that
  • on type NoLt = &T;, suggest using a named lifetime from the impl if present
  • on type NoLt = &T;, suggest adding 'a to the impl if the trait or self type have anon lifetimes
  • expand the documentation of E0207 to mention these cases

Metadata

Assignees

No one assigned

    Labels

    A-diagnosticsArea: Messages for errors, warnings, and lintsA-lifetimesArea: Lifetimes / regionsA-suggestion-diagnosticsArea: Suggestions generated by the compiler applied by `cargo fix`D-invalid-suggestionDiagnostics: A structured suggestion resulting in incorrect code.D-newcomer-roadblockDiagnostics: Confusing error or lint; hard to understand for new users.D-terseDiagnostics: An error or lint that doesn't give enough information about the problem at hand.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions