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 wrotefor<'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)
- (though I would still make this one
EDIT: more information found since opening the issue (in #100742 (comment)):
- bisected to Remove migrate borrowck mode #95565
- what I'm calling the "good" error replaced the "bad" one back in 1.52.0
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)