-
Notifications
You must be signed in to change notification settings - Fork 14.1k
Description
I noticed that when matching and returning (const) fn items directly, the compiler was able to coerce them into the same fn type fn(u64, u64) -> u64 automatically, but when included as part of a tuple, the compiler seemingly lost this ability.
I'd probably call this more "surprising" than a "bug", since the diagnostics do hint at the right way to remediate this. Still - I wanted to report since it was suprising to me that it could handle it in the simple case and not in the next more complex type.
I tried this code:
fn main() {
let op = "*";
// Single item: totally fine!
let func = match op {
"+" => u64::wrapping_add,
"*" => u64::wrapping_mul,
_ => unimplemented!(),
};
println!("{}", func(2, 20));
// NOT FINE
//
// = note: expected tuple `({integer}, fn(_, _) -> _ {core::num::<impl u64>::wrapping_add})`
// found tuple `({integer}, fn(_, _) -> _ {core::num::<impl u64>::wrapping_mul})`
// = note: different fn items have unique types, even if their signatures are the same
// = help: consider casting both fn items to fn pointers using `as fn(u64, u64) -> u64`
//
// let (base, func) = match op {
// "+" => (0, u64::wrapping_add),
// "*" => (1, u64::wrapping_mul),
// _ => unimplemented!(),
// };
// println!("{}", func(base, 20));
// Fine if we specify the type (or do manual casting)
let (base, func): (u64, fn(u64, u64) -> u64) = match op {
"+" => (0, u64::wrapping_add),
"*" => (1, u64::wrapping_mul),
_ => unimplemented!(),
};
println!("{}", func(base, 20));
}I expected to see this happen: Compiler is consistent whether the fn items are directly returned or as part of an aggregate/tuple item.
Instead, this happened: Compiler only performed auto-coercion of the fn item when it was not part of an aggregate/tuple item
Meta
Repros on current stable/nightlies: 1.91.1, 2025-12-06.