Confusing diagnostic when forgetting to capture lifetime in a APIT
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 119k
- Forks
- 16.1k
- PR merge metrics
- PR metrics pending
Description
Code
trait A<'a> {
type Assoc;
}
trait B {}
fn f(_: impl for<'a> A<'a, Assoc = impl B>) {}
impl<'a> A<'a> for () {
type Assoc = &'a u8;
}
impl B for &u8 {}
fn main() {
f(());
}
Current output
error[E0308]: mismatched types
--> ./t.rs:16:5
|
16 | f(());
| ^^^^^ one type is more general than the other
|
= note: expected reference `&'a _`
found reference `&_`
note: the lifetime requirement is introduced here
--> ./t.rs:7:28
|
7 | fn f(_: impl for<'a> A<'a, Assoc = impl B>) {}
| ^^^^^^^^^^^^^^
Desired output
error[E0308]: mismatched types
--> ./t.rs:16:5
|
16 | f(());
| ^^^^^ one type is more general than the other
|
= note: expected reference `for<'a> &'a _`
found reference `&'0 _` for some specific lifetime `'0`
= note: `impl B` can't name `'a`
note: the lifetime requirement is introduced here
--> ./t.rs:7:28
|
7 | fn f(_: impl for<'a> A<'a, Assoc = impl B>) {}
| ^^^^^^^^^^^^^^
Rationale and extra context
It is not very clear from the error why impl B introduces the lifetime requirement or why we "found" a &_ (this leaks generalizer impl kinda). Ideally we would explain the actual cause of the error (impl B introduces a new generic parameter outside of the scope of for<'a>).
I don't like having for<'a> &'a _ in the desired error either, because it implies that it's a type that exists, but I couldn't come up with a better explanation for the fact that 'a is from the for<'a>...
Maybe we could even suggest impl for<'a> A<'a, Assoc: B>) but @BoxyUwU says it's probably hard. We could just lint on impl Trait<Assoc = impl Other> as a style thing suggesting Assoc: Other since it allows more things.
Other cases
If you add `+ 'a` the diagnostic is a bit better:
trait A<'a> {
type Assoc;
}
trait B {}
fn f(_: impl for<'a> A<'a, Assoc = impl B + 'a>) {}
impl<'a> A<'a> for () {
type Assoc = &'a u8;
}
impl B for &u8 {}
fn main() {
f(());
}
error: `impl Trait` can only mention lifetimes from an fn or impl
--> ./t.rs:7:45
|
7 | fn f(_: impl for<'a> A<'a, Assoc = impl B + 'a>) {}
| -- lifetime declared here ^^
error[E0308]: mismatched types
--> ./t.rs:16:5
|
16 | f(());
| ^^^^^ one type is more general than the other
|
= note: expected reference `&'a _`
found reference `&_`
note: the lifetime requirement is introduced here
--> ./t.rs:7:28
|
7 | fn f(_: impl for<'a> A<'a, Assoc = impl B + 'a>) {}
| ^^^^^^^^^^^^^^^^^^^
Rust Version
rustc 1.79.0-nightly (ef8b9dcf2 2024-04-24)
binary: rustc
commit-hash: ef8b9dcf23700f2e2265317611460d3a65c19eff
commit-date: 2024-04-24
host: x86_64-unknown-linux-gnu
release: 1.79.0-nightly
LLVM version: 18.1.4
Anything else?
No response
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Reproduce the diagnostic from the complete example in ./t.rs using the reported rustc 1.79.0-nightly version, then trace the compiler's handling of the APIT and associated opaque type lifetime requirement. Done means the error explains that impl B cannot name 'a and presents the lifetime mismatch in the requested form, while preserving the existing source-span context.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 42/100