Skip to content

Compiler can't consistently auto-coerce fn pointers #149731

@jamesmunns

Description

@jamesmunns

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:

playground link

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-coercionsArea: implicit and explicit `expr as Type` coercionsA-inferenceArea: Type inferenceC-enhancementCategory: An issue proposing an enhancement or a PR with one.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.T-typesRelevant to the types team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions