Closed
Description
Code
fn f<'long: 'short, 'short>(_: &'short &'long ()) {
let higher_ranked: for<'any> fn(&'any ()) = |_| {};
let long: fn(&'long ()) = |_| {};
let short: fn(&'short()) = |_| {};
let stat: fn(&'static ()) = |_| {};
// Contravariance: `fn(&'short ())` is a subtype of `fn(&'long ())`, etc.
let _: fn(&'static ()) = long;
let _: fn(&'long ()) = short;
// The higher-ranked type is a subtype of all of them
let _: fn(&'static ()) = higher_ranked;
let _: fn(&'long ()) = higher_ranked;
let _: fn(&'short ()) = higher_ranked;
}
I expected to see this happen: Successful compilation
Instead, this happened: Compiler error:
error[E0308]: mismatched types
--> <source>:12:12
|
12 | let _: fn(&'static ()) = higher_ranked;
| ^^^^^^^^^^^^^^^ one type is more general than the other
|
= note: expected fn pointer `fn(&'static ())`
found fn pointer `for<'any> fn(&'any ())`
error[E0308]: mismatched types
--> <source>:13:12
|
13 | let _: fn(&'long ()) = higher_ranked;
| ^^^^^^^^^^^^^ one type is more general than the other
|
= note: expected fn pointer `fn(&'long ())`
found fn pointer `for<'any> fn(&'any ())`
error[E0308]: mismatched types
--> <source>:14:12
|
14 | let _: fn(&'short ()) = higher_ranked;
| ^^^^^^^^^^^^^^ one type is more general than the other
|
= note: expected fn pointer `fn(&'short ())`
found fn pointer `for<'any> fn(&'any ())`
Version it worked on
It most recently worked on: Rust 1.35.
It works on every version before that which I spot checked (but I did not spot check all of them).
Versions before 1.18.0 cannot coerce a closure to a function pointer, but this variation:
fn g(_: &()) {}
fn f<'long: 'short, 'short>(_: &'short &'long ()) {
let higher_ranked: for<'any> fn(&'any ()) = g;
// The higher-ranked type is a subtype of all of them
let _: fn(&'static ()) = higher_ranked;
let _: fn(&'long ()) = higher_ranked;
let _: fn(&'short ()) = higher_ranked;
}
Works all the way back to Rust 1.0.0.
Versions with regression
Rust 1.36.0 and all those which I spot-checked after this version.
The error changes in Rust 1.56.0 due to one of the #57374 fixes; I didn't track down which.
Current playground, any version.
- Stable version: 1.59.0
- Beta version: 1.60.0-beta.5 (2022-03-18 6ee5a40)
- Nightly version: 1.61.0-nightly (2022-03-18 1bfe40d)
Workaround
let _: fn(&'static ()) = higher_ranked as _;
let _: fn(&'long ()) = higher_ranked as _;
let _: fn(&'short ()) = higher_ranked as _;
But RFC 401 says this should not be necessary.
@rustbot modify labels: +regression-from-stable-to-stable -regression-untriaged