Skip to content

Function item subtyping can change behavior #155986

@theemathas

Description

@theemathas

I'm not sure if this is a bug or not.

In the following code, F2 is a subtype of F1. It seems that this causes the type of the F2::method function item to be a subtype of the F1::method function item. This implies that function items that are subtypes of each other can have different behavior. This is rather strange.

type F1 = fn(&'static ());
type F2 = for<'a> fn(&'a ());

trait Trait: Sized {
    fn method() -> Option<Self>;
}

impl Trait for F1 {
    fn method() -> Option<Self> {
        println!("F1");
        None
    }
}

#[expect(coherence_leak_check)]
impl Trait for F2 {
    fn method() -> Option<Self> {
        println!("F2");
        None
    }
}

fn main() {
    let mut x = F1::method;
    x();
    let y = F2::method;
    y();
    x = y;
    x();
}

The above code prints:

F1
F2
F1

cc @lcnr

Meta

Reproducible on the playground with version 1.97.0-nightly (2026-04-28 37d85e592f9ae5f20f7d)

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-closuresArea: Closures (`|…| { … }`)A-higher-rankedArea: Higher-ranked things (e.g., lifetimes, types, trait bounds aka HRTBs)A-trait-systemArea: Trait systemA-varianceArea: Variance (https://doc.rust-lang.org/nomicon/subtyping.html)C-bugCategory: This is a bug.T-typesRelevant to the types team, which will review and decide on the PR/issue.needs-triageThis issue may need triage. Remove it if it has been sufficiently triaged.

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions