Skip to content

Conversation

@Kivooeo
Copy link
Member

@Kivooeo Kivooeo commented Oct 29, 2025

Currently, there are blanket implementations for &F and &mut F for FnMut and FnOnce, but not for Fn, as a result, &mut F implements fewer of the Fn traits than &F, which is inconsistent and this PR fills that coherence hole

Technically, this is a breaking change because Fn is a fundamental trait, however, practical breakage is expected to be minimal, as such overlapping impl patterns are extremely rare

pub trait Trait {}
impl<F: Fn()> Trait for F {}
impl Trait for &fn() {}     // not allowed
impl Trait for &mut fn() {} // allowed

Because of this, second impl for &mut fn() works fine but shouldn't

Fixes #147931

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue. WG-trait-system-refactor The Rustc Trait System Refactor Initiative (-Znext-solver) labels Oct 29, 2025
@rustbot
Copy link
Collaborator

rustbot commented Oct 29, 2025

r? @scottmcm

rustbot has assigned @scottmcm.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@Noratrieb Noratrieb added the needs-crater This change needs a crater run to check for possible breakage in the ecosystem. label Oct 29, 2025
@Noratrieb
Copy link
Member

@bors try

@rust-bors

This comment has been minimized.

rust-bors bot added a commit that referenced this pull request Oct 29, 2025
Add missing `impl Fn for &mut F where F: Fn`
@Noratrieb
Copy link
Member

r? libs-api

@rustbot rustbot added the T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. label Oct 29, 2025
@rustbot rustbot assigned the8472 and unassigned scottmcm Oct 29, 2025
@rust-bors
Copy link

rust-bors bot commented Oct 30, 2025

☀️ Try build successful (CI)
Build commit: ddcf048 (ddcf048784667508cd676fef4667f88ae15628a3, parent: 292be5c7c05138d753bbd4b30db7a3f1a5c914f7)

}
}

#[stable(feature = "rust1", since = "1.0.0")]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this "since" line correct?

Copy link
Member Author

@Kivooeo Kivooeo Oct 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is going to be insta stable so I think so and it should be available on all versions

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you mean by "should be available on all versions"?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, you mean that if I make it since = 1.91 it will work not only in 1.91+? because in my opinion this should be available in all versions since 1.0

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This attribute is only describing when it was added for docs. We cannot add things to old versions.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh, ok then, I will change it after crater

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

huh, seems like I can't?

error[E0711]: feature `async_closure` is declared stable since 1.93.0, but was previously declared stable since 1.85.0
   --> library/core/src/ops/async_function.rs:130:5
    |
130 |     #[stable(feature = "async_closure", since = "1.93.0")]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0711]: feature `rust1` is declared stable since 1.93.0, but was previously declared stable since 1.0.0
   --> library/core/src/ops/function.rs:314:5
    |
314 |     #[stable(feature = "rust1", since = "1.93.0")]
    |    

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it don't feel correct to change stable since for all impls

@theemathas theemathas added the needs-fcp This change is insta-stable, or significant enough to need a team FCP to proceed. label Oct 30, 2025
@saethlin
Copy link
Member

@craterbot run mode=check-only

@craterbot
Copy link
Collaborator

👌 Experiment pr-148271 created and queued.
🤖 Automatically detected try build ddcf048
🔍 You can check out the queue and this experiment's details.

ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@craterbot craterbot added S-waiting-on-crater Status: Waiting on a crater run to be completed. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Oct 30, 2025
@craterbot
Copy link
Collaborator

🚧 Experiment pr-148271 is now running

ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@craterbot
Copy link
Collaborator

🎉 Experiment pr-148271 is completed!
📊 6 regressed and 4 fixed (726473 total)
📊 1786 spurious results on the retry-regessed-list.txt, consider a retry1 if this is a significant amount.
📰 Open the summary report.

⚠️ If you notice any spurious failure please add them to the denylist!
ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

Footnotes

  1. re-run the experiment with crates=https://crater-reports.s3.amazonaws.com/pr-148271/retry-regressed-list.txt

@craterbot craterbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-crater Status: Waiting on a crater run to be completed. labels Oct 31, 2025
@Noratrieb
Copy link
Member

@craterbot
Copy link
Collaborator

👌 Experiment pr-148271-1 created and queued.
🤖 Automatically detected try build ddcf048
🔍 You can check out the queue and this experiment's details.

ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@craterbot craterbot added S-waiting-on-crater Status: Waiting on a crater run to be completed. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Oct 31, 2025
@craterbot
Copy link
Collaborator

🚧 Experiment pr-148271-1 is now running

ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@craterbot
Copy link
Collaborator

🎉 Experiment pr-148271-1 is completed!
📊 1 regressed and 0 fixed (1777 total)
📊 102 spurious results on the retry-regessed-list.txt, consider a retry1 if this is a significant amount.
📰 Open the summary report.

⚠️ If you notice any spurious failure please add them to the denylist!
ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

Footnotes

  1. re-run the experiment with crates=https://crater-reports.s3.amazonaws.com/pr-148271-1/retry-regressed-list.txt

@craterbot craterbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-crater Status: Waiting on a crater run to be completed. labels Nov 5, 2025
@theemathas
Copy link
Contributor

The only non-spurious failure was from the currying crate. I've minimized the code from that crate to below:

#![feature(unboxed_closures)]
#![feature(fn_traits)]

#[allow(dead_code)]
pub struct Curried<F> {
    func: F,
}

impl<F: FnOnce()> FnOnce<()> for Curried<F> {
    type Output = ();
    extern "rust-call" fn call_once(self, _: ()) {}
}
impl<F: FnMut()> FnMut<()> for Curried<F> {
    extern "rust-call" fn call_mut(&mut self, _: ()) {}
}
impl<F: Fn()> Fn<()> for Curried<F> {
    extern "rust-call" fn call(&self, _: ()) {}
}

pub fn test_mut() {
    let mut i = 0;
    let mut f = || {
        i += 1;
    };
    let mut fj = Curried { func: &mut f };
    fj();
}

Error after this PR:

error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnMut`
  --> src\lib.rs:22:17
   |
22 |     let mut f = || {
   |                 ^^ this closure implements `FnMut`, not `Fn`
23 |         i += 1;
   |         - closure is `FnMut` because it mutates the variable `i` here
...
26 |     fj();
   |     ---- the requirement to implement `Fn` derives from here
   |
   = note: required for `&mut {closure@src\lib.rs:22:17: 22:19}` to implement `Fn()`
   = note: 1 redundant requirement hidden
   = note: required for `Curried<&mut {closure@src\lib.rs:22:17: 22:19}>` to implement `Fn()`

For more information about this error, try `rustc --explain E0525`.
error: could not compile `currying` (lib) due to 1 previous error

I don't understand why it's erroring though...

@BoxyUwU
Copy link
Member

BoxyUwU commented Nov 6, 2025

gonna nominate this for T-types. I am not sure to what extent we actually depend on the exact set of Fn* impls in core/std from within the compiler. It would seem plausible to me that method lookup or the trait solver could be making assumptions about the kind of impls that exist.

@BoxyUwU BoxyUwU added the I-types-nominated Nominated for discussion during a types team meeting. label Nov 6, 2025
@programmerjake
Copy link
Member

programmerjake commented Nov 6, 2025

can you add AsyncFn for &mut impl AsyncFn too?

@Kivooeo
Copy link
Member Author

Kivooeo commented Nov 8, 2025

@programmerjake, I have zero understanding of what is happening in async code, is this correct impl (I just copied from AsyncFn for &F and changed it to &mut self

    impl<'a, A: Tuple, F: ?Sized> AsyncFn<A> for &'a mut F
    where
        F: AsyncFn<A>,
    {
        extern "rust-call" fn async_call(&self, args: A) -> Self::CallRefFuture<'_> {
            F::async_call(*self, args)
        }
    }

For context: https://doc.rust-lang.org/src/core/ops/async_function.rs.html#60

@programmerjake
Copy link
Member

@programmerjake, I have zero understanding of what is happening in async code, is this correct impl (I just copied from AsyncFn for &F and changed it to &mut self

it looks correct to me

@rust-cloud-vms rust-cloud-vms bot force-pushed the impl-fn-for-mut-ref-fn branch from 119ae33 to 77295f7 Compare November 8, 2025 18:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

I-types-nominated Nominated for discussion during a types team meeting. needs-crater This change needs a crater run to check for possible breakage in the ecosystem. needs-fcp This change is insta-stable, or significant enough to need a team FCP to proceed. S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. WG-trait-system-refactor The Rustc Trait System Refactor Initiative (-Znext-solver)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

&mut impl Fn() does not implement Fn()

10 participants