Skip to content

HRTBs, implementation is not general enough #98403

Open
@okryvyts

Description

@okryvyts

I tried this code:

fn shortened_first<'b, 'a: 'b>(first: &'a str, second: &'b str, _: &'b &'a ()) -> &'b str {
    first
}

fn call_shortened_first<F>(f: F)
where
    F: for<'a, 'b> FnOnce(&'a str, &'b str, &'b &'a ()) -> &'b str
{
    let a = "a".to_owned();
    let b = "b".to_owned();
    
    let result = f(&a, &b, &&());
    println!("{result}");
}

fn main() {
    call_shortened_first(shortened_first);
}

I expected to see this happen: I expected this code to compile

Instead, this happened:

   Compiling playground v0.0.1 (/playground)
error: implementation of `FnOnce` is not general enough
  --> src/main.rs:17:5
   |
17 |     call_shortened_first(shortened_first);
   |     ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
   |
   = note: `fn(&str, &'3 str, &'3 &()) -> &'3 str {shortened_first::<'3, '_>}` must implement `FnOnce<(&'a str, &'1 str, &'1 &'a ())>`, for any two lifetimes `'1` and `'2`...
   = note: ...but it actually implements `FnOnce<(&str, &'3 str, &'3 &())>`, for some specific lifetime `'3`

However, If I remove an explicit 'a: 'b bound the code compiles.

fn shortened_first<'b, 'a>(first: &'a str, second: &'b str, _: &'b &'a ()) -> &'b str {
    first
}

fn call_shortened_first<F>(f: F)
where
    F: for<'a, 'b> FnOnce(&'a str, &'b str, &'b &'a ()) -> &'b str
{
    let a = "a".to_owned();
    let b = "b".to_owned();
    
    let result = f(&a, &b, &&());
    println!("{result}");
}

fn main() {
    call_shortened_first(shortened_first);
}

Meta

Reproducible on 1.61-stable, 1.62.0-beta.5(2022-06-13 1bc802e990a3393731b1), 1.63.0-nightly(2022-06-20 5750a6aa2777382bf421)

I suspect it has something to do with 'a: 'b makes 'b early bound, but when 'a: 'b is implied from &'b &'a () it doesn't make 'b early bound. The behavior is inconsistent and therefore very confusing.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-higher-rankedArea: Higher-ranked things (e.g., lifetimes, types, trait bounds aka HRTBs)A-implied-boundsArea: Implied bounds / inferred outlives-boundsA-lifetimesArea: Lifetimes / regionsC-bugCategory: This is a bug.T-typesRelevant to the types team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions