Skip to content

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

Open

Description

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)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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