rust-lang / rust-lang/rust

Confusing diagnostic when forgetting to capture lifetime in a APIT

Open
#124,479 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-diagnostics A-lifetimes D-terse T-compiler
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

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

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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.