rust-lang / rust-lang/rust

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

Open
#135,589 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-associated-items A-diagnostics A-lifetimes A-suggestion-diagnostics P-low T-compiler
Dominant language
Rust
Stars
119k
Forks
16.1k
PR merge metrics
PR metrics pending

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 https://github.com/mainmatter/100-exercises-to-learn-rust/issues/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

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by running the linked Rust Playground reproductions and reading the existing E0261 and E0207 diagnostics and documentation. Compare the results with the issue checklist, then update the compiler suggestions and E0207 documentation so lifetime guidance matches the trait and self-type declarations in each case.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers, documentation
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.