Skip to content

Redundant error for "implementation ... not general enough" in "NLL" mode / since 1.63 (when it was made permanent). #100742

Open
@eddyb

Description

@eddyb

This is a classic demonstration of the limitations of ("early-bound") generics wrt HRTB:

fn type_generic<T>(_: T) {}

struct LtGen<'a>(&'a ());
fn takes_ltgen_forall_lifetimes(_: impl for<'x> FnOnce(LtGen<'x>)) {}

fn main() {
    takes_ltgen_forall_lifetimes(type_generic);
}

(I don't know what issue we have open about it - #30904 is too specific, there must be one about generic functions - and also if we ever fix this it will likely require for<'x> typeof(type_generic::<LtGen<'x>>) function types, which I've brought up to @nikomatsakis before but I haven't seen any other discussion of)

Either way, for now, the above should error (if you're curious, the simplest fix is to use a closure, that itself can be for<'x>, and which calls the function, like |x| type_generic(x)).

And for a long time (since MIR borrowck?) we've had this error:

error: implementation of `FnOnce` is not general enough
 --> <source>:7:5
  |
7 |     takes_ltgen_forall_lifetimes(type_generic);
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
  |
  = note: `fn(LtGen<'2>) {type_generic::<LtGen<'2>>}` must implement `FnOnce<(LtGen<'1>,)>`, for any lifetime `'1`...
  = note: ...but it actually implements `FnOnce<(LtGen<'2>,)>`, for some specific lifetime `'2`

It's not perfect, but it shows the difference between some inferred lifetime ('2) and the HRTB ('1).


However, since 1.63.0 (see comparison on godbolt: https://godbolt.org/z/EzjPzE7xs), we also get:

error[E0308]: mismatched types
 --> <source>:7:5
  |
7 |     takes_ltgen_forall_lifetimes(type_generic);
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
  |
  = note: expected trait `for<'x> FnOnce<(LtGen<'x>,)>`
             found trait `FnOnce<(LtGen<'_>,)>`
note: the lifetime requirement is introduced here
 --> <source>:4:41
  |
4 | fn takes_ltgen_forall_lifetimes(_: impl for<'x> FnOnce(LtGen<'x>)) {}
  |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^

This is a weirder error, that I naively assumed would be the old regionck (but that got removed, right? so it can't be that), though I suppose it could be some generic obligation solving from inside MIR borrowck.

  • it's presented as a type mismatch when it's an unsatisfied bound specifically because of HRTB
  • '_ is used for lifetime inference variables
  • can use the ugly for<'r> auto-naming in the printout (not here because I wrote for<'x>)
  • it's not necessary because the better error is still being emitted
    • (though I would still make this one delay_span_bug if they're not emitted from exactly the same place)

EDIT: more information found since opening the issue (in #100742 (comment)):

EDIT2: better timeline in #100742 (comment) - the error was improved back in #81972 but the "bonus error" comes from "NLL mode" - e.g. #57374 (comment).


cc @estebank @rust-lang/wg-nll @lcnr (this may be subtle in nature, hopefully someone knows what happened)

cc @Manishearth (who has a similar error though unlikely related to this 1.62.0->1.63.0 change, since it's on 1.61.0 instead, and does not even have the good error showing up at all - that one still needs to be reduced)

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-borrow-checkerArea: The borrow checkerA-diagnosticsArea: Messages for errors, warnings, and lintsA-lifetimesArea: Lifetimes / regionsD-verboseDiagnostics: Too much output caused by a single piece of incorrect code.T-compilerRelevant to the compiler 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