Top to Bottom @WaffleLapkin @BoxyUwU
fn func(a: &'static u32) {
dbg!(a);
}
fn accepts_func(f: for<'a> fn(&'a u32), data: &u32) {
f(data);
}
fn main() {
let local = 274;
// &'static u32 can be shortened to any
// lifetime borrow so func should be fine
accepts_func(func, &local);
}
Solution
error[E0308]: mismatched types
--> examples/borrowck_1.rs:13:18
|
13 | accepts_func(func, &local);
| ------------ ^^^^ one type is more general than the other
| |
| arguments to this function are incorrect
|
= note: expected fn pointer `for<'a> fn(&'a _)`
found fn item `fn(&'static _) {func}`
note: function defined here
--> examples/borrowck_1.rs:5:4
|
5 | fn accepts_func(f: for<'a> fn(&'a u32), data: &u32) {
| ^^^^^^^^^^^^ ----------------------
For more information about this error, try `rustc --explain E0308`.
error: could not compile `code` (example "borrowck_1") due to 1 previous error
The accepts_func function requires a function that can be called with a reference with any lifetime.
Notably func can't be called with any lifetime — it can only be called with 'static.
In most situations the lifetime of a reference can be shortened, allowing &'static u32 to turn into a reference of any lifetime.
However, argument types of function pointers work the opposite way; instead of lifetimes shrinking they can only be extended.
We can turn a function pointer fn(&'a u32) into fn(&'static u32), even when 'a doesn't outlive 'static.
This can be thought of as the function pointer performing the subtyping that the caller could have done themselves:
fn foo<'a>(fnptr: fn(&'a u32), borrow: &'static u32) {
// As the caller we can shrink the lifetime of `borrow` before
// passing it to `fnptr` which expects a borrow of lifetime `'a`
let borrow: &'a u32 = borrow;
fnptr(borrow);
// Alternatively we can have the function pointer itself do
// this for all of its callers!
let fnptr: fn(&'static u32) = borrow;
fnptr(borrow);
// It may also be helpful to realise we can *explicitly* perform
// this implicit subtyping by writing it as a closure
let closure = |borrow: &'static u32| {
let borrow: &'a u32 = borrow;
fnptr(borrow);
};
closure(borrow);
}
Argument types of function pointers having special subtyping rules is more commonly referred to contravariance, opposed to the normal covariance that allows for shrinking lifetimes. More information on variance can be found in the Subtyping and Variance chapter of the Rustonomicon.