This proposes a new amendment to RFC 1214.
General Proposal
Currently, given a function with type fn(T1..Tn) -> T0
, where T1: 'a, .., Tn: 'y
and T0: 'z
, a pointer to said function is bounded by 'fn: 'a + .. + 'z
. This RFC proposes to amend RFC 1214 to render this bound only as 'fn: 'z
, as the argument bounds are unnecessary for soundness.
This does not propose to add the same relaxation to any other types or traits.
This PR was motivated by rust-lang/rust#80317. A simple example of code that currently fails to compile:
pub fn foo<'a, T: 'a>() {}
pub fn bar<'a, 'b>() {
foo::<'a, fn(&'b u32)>(); // Errors
}
Soundness
Why is this change sound? An fn pointer that outlives any argument lifetimes cannot be called, as arguments can no longer be constructed / have live references. The lifetime checking of the body is unaffected, so this doesn't induce any changes to the lifetime checking of the function/stateless closure itself.
Open Questions
Can we remove the bound on the return type as well? This seems like it should be sound, as any attempt to call the fn would fail WF check on the use of the returned type. The one situation I'm not sure about is one where the function can be called, but its return is not used. I'm not sure if that would pass the lifetime check, and if it does, then it could execute arbitrary code with unsound lifetimes.
Can this be extended to Fn/FnOnce/FnMut
? This would require special-casing these traits, and add limits on possible future extensions to them. Also, as implementers of those traits may have arbitrary extra data attached, they may access state similar to closures. I'm not sure if the borrow checker would handle lifetime checking for that correctly, if changed.