rust-lang / rust-lang/rust

Elided early-bound lifetime parameters (due to associated types) can be turbofished

Open
#154,490 3 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

A-associated-items A-lifetimes A-type-system C-bug T-lang T-types
Dominant language
Rust
Stars
119k
Forks
16.1k
PR merge metrics
PR metrics pending

Description

Normally, a function with elided lifetime parameters cannot be turbofished, since elided lifetime parameters are normally late-bound, and late-bound parameters cannot be turbofished. However, using associated types, it is seemingly possible to have an elided early-bound ilifetime parameter, which can then be turbofished, such as in the following code.

// compiles without errors

trait Trait {
    type Assoc<'a>;
}

// zero explicit generic lifetimes
fn do_thing<T: Trait>(_: Option<<T as Trait>::Assoc<'_>>) -> &i32 {
    todo!()
}

fn foo<T: Trait>() {
    // one explicit generic lifetime
    do_thing::<'static, T>(None);
}

In the above code, there is a turbofish specifying a lifetime parameter. The parameter being specified is an elided lifetime parameter. This seems wrong, and is especially confusing when there's also an explicit lifetime parameter, such as in the following code.

// compiles without errors

trait Trait {
    type Assoc<'a>;
}

// one explicit generic lifetime
fn do_thing<'b, T: Trait>(_: Option<<T as Trait>::Assoc<'_>>) -> (&i32, &'b i64) {
    todo!()
}

fn foo<T: Trait>() {
    // two explicit generic lifetimes
    do_thing::<'static, 'static, T>(None);
}

In the above code, it is not obvious which of the two lifetimes specified as 'static corresponds to the 'b lifetime vs the elided lifetime. (I think the first 'static corresponds to 'b, and the second 'static corresponds to the elided lifetime.) This seems undesirable.

For some reason, a return type with an elided lifetime is seemingly required for this weirdness to happen. See the following code.

// fails to compile

trait Trait {
    type Assoc<'a>;
}

// zero explicit generic lifetimes
fn do_thing<T: Trait>(_: Option<<T as Trait>::Assoc<'_>>) -> i32 {
    todo!()
}

fn foo<T: Trait>() {
    // one explicit generic lifetime
    do_thing::<'static, T>(None);
}
error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
  --> src/lib.rs:14:16
   |
14 |     do_thing::<'static, T>(None);
   |                ^^^^^^^
   |
note: the late bound lifetime parameter is introduced here
  --> src/lib.rs:8:53
   |
 8 | fn do_thing<T: Trait>(_: Option<<T as Trait>::Assoc<'_>>) -> i32 {
   |                                                     ^^

For more information about this error, try `rustc --explain E0794`.

Here are some other variations of the weirdness:

Using a trait associated function instead of a top-level function
// compiles without errors

trait Trait {
    type Assoc<'a>;
    // zero explicit generic lifetimes
    fn do_thing(_: Option<Self::Assoc<'_>>) -> &i32 {
        todo!()
    }
}

fn foo<T: Trait>() {
    // one explicit generic lifetime
    <T as Trait>::do_thing::<'static>(None);
}
Using a normal associated type instead of a GAT
// compiles without errors

trait Trait {
    type Assoc;
}

// zero explicit generic lifetimes
fn do_thing<T>(_: Option<<&T as Trait>::Assoc>) -> &i32
where
    for<'c> &'c T: Trait,
{
    todo!()
}

fn foo<T: 'static>()
where
    for<'c> &'c T: Trait,
{
    // one explicit generic lifetime
    do_thing::<'static, T>(None);
}
Implementing a trait with a method with an elided early-bound lifetime parameter
// compiles without errors

trait Trait {
    type Assoc<'a>;
    // zero explicit generic lifetimes
    fn do_thing(_: Option<Self::Assoc<'_>>) -> &i32;
}

impl Trait for i32 {
    type Assoc<'a> = i64;
    // one explicit generic lifetime
    fn do_thing<'b>(_: Option<i64>) -> &'b i32 {
        todo!()
    }
}

cc @lcnr

Meta

Reproducible on the playground with version 1.96.0-nightly (2026-03-26 23903d01c237d7c7d4fb)

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 examples in src/lib.rs with the reported rustc nightly version, starting with the cases that compile and the E0794 case. Compare how lifetime parameters are classified when associated types and elided return lifetimes are present. Done requires an agreed rule for these turbofish arguments and compiler coverage for the reported variations.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.