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

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

Open
1 of 9 tasks
estebank opened this issue Jan 16, 2025 · 0 comments
Open
1 of 9 tasks
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-lifetimes Area: Lifetimes / regions A-suggestion-diagnostics Area: Suggestions generated by the compiler applied by `cargo fix` D-invalid-suggestion Diagnostics: A structured suggestion resulting in incorrect code. D-newcomer-roadblock Diagnostics: Confusing error or lint; hard to understand for new users. D-terse Diagnostics: An error or lint that doesn't give enough information about the problem at hand. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@estebank
Copy link
Contributor

estebank commented Jan 16, 2025

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
@estebank estebank added A-diagnostics Area: Messages for errors, warnings, and lints A-lifetimes Area: Lifetimes / regions A-suggestion-diagnostics Area: Suggestions generated by the compiler applied by `cargo fix` D-invalid-suggestion Diagnostics: A structured suggestion resulting in incorrect code. D-newcomer-roadblock Diagnostics: Confusing error or lint; hard to understand for new users. D-terse Diagnostics: An error or lint that doesn't give enough information about the problem at hand. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Jan 16, 2025
estebank added a commit to estebank/rust that referenced this issue Jan 16, 2025
estebank added a commit to estebank/rust that referenced this issue Jan 16, 2025
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Jan 17, 2025
Expand docs for `E0207` with additional example

Add an example to E0207 docs showing how to tie the lifetime of the self type to an associated type in an impl when the trait *doesn't* have a lifetime to begin with.

CC rust-lang#135589.
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Jan 17, 2025
Expand docs for `E0207` with additional example

Add an example to E0207 docs showing how to tie the lifetime of the self type to an associated type in an impl when the trait *doesn't* have a lifetime to begin with.

CC rust-lang#135589.
rust-timer added a commit to rust-lang-ci/rust that referenced this issue Jan 17, 2025
Rollup merge of rust-lang#135604 - estebank:docs-e0207, r=jieyouxu

Expand docs for `E0207` with additional example

Add an example to E0207 docs showing how to tie the lifetime of the self type to an associated type in an impl when the trait *doesn't* have a lifetime to begin with.

CC rust-lang#135589.
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: Lifetimes / regions A-suggestion-diagnostics Area: Suggestions generated by the compiler applied by `cargo fix` D-invalid-suggestion Diagnostics: A structured suggestion resulting in incorrect code. D-newcomer-roadblock Diagnostics: Confusing error or lint; hard to understand for new users. D-terse Diagnostics: An error or lint that doesn't give enough information about the problem at hand. 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

1 participant