Description
This issue proposes to change the LUB/GLB strategy in rustc to adopt something that is more conservative, but also more correct, and also more forwards compatible.
How this affects you
In some limited cases, you may need to alter your Rust code to "cast" the types of functions more explicitly. This can occur specifically when combining function pointers or trait objects that involve lifetimes. For example, the following function no longer compiles:
fn foo(
x: fn(&u8, &u8),
y: for<'a> fn(&'a u8, &'a u8),
) {
let z = match 22 {
0 => x,
_ => y,
};
}
The fix is to "upcast" x
and y
into a common type. In this case, since x
accepts arguments with two distinct lifetimes, but y
requires a single lifetime, we would want to pick the type of y
(which is more selective).
fn foo(
x: fn(&u8, &u8),
y: for<'a> fn(&'a u8, &'a u8),
) {
let z = match 22 {
0 => x as for<'a> fn(&'a u8, &'a u8),
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ explicit cast
_ => y,
};
}
Background: why is this change being made?
Simply put, the existing code for handling function types of this kind if known to be buggy and incomplete. Since this scenario -- combining two function pointers with distinct signatures -- occurs quite rarely (in fact, no known instances were encountered), it was decided to adopt a simpler, more conservative approach that is known to be correct.
More specifically, we adopted a rule that computing the least-upper-bound (common supertype) of two higher-ranked types (e.g., function pointers, trait objects) is done by requiring them to be equal.
What happens now?
Given that we did not find any occurrences of this code in our crater run, and that a full warning period is difficult to achieve, we opted to move straight to a hard-error with this code. If you are having problems fixing your code, or would like to object to this decision, please leave a comment (cc @nikomatsakis) or -- perhaps better yet -- reach out on IRC (nmatsakis
).