Skip to content

Custom Fn* trait implementation doesn't properly fallback from Fn to FnMut, or FnMut to FnOnce #89032

Open
@wwylele

Description

@wwylele

I tried this code:

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

struct Wrapper<F>(F);

impl<Args, F:FnOnce<Args>> FnOnce<Args> for Wrapper<F> {
    type Output = F::Output;
    extern "rust-call" fn call_once(self, args: Args) -> Self::Output {
        self.0.call_once(args)
    }
}

// Uncomment this implementation and the code in main() breaks... what?
/*
impl<Args, F:FnMut<Args>> FnMut<Args> for Wrapper<F> where Self:FnOnce<Args, Output=F::Output> {
    extern "rust-call" fn call_mut(&mut self, args: Args) -> <Self as FnOnce<Args>>::Output {
        self.0.call_mut(args)
    }
}
*/

fn main() {
    struct Stuff;
    let stuff = Stuff;
    let f = ||drop(stuff);
    let g = Wrapper(f);
    g();
}

I expected to see this happen: Whether the commented code is commented or not, the code should compile

Instead, this happened: If the commented code is uncommented, it fails to compile. The error is

error[E0525]: expected a closure that implements the `FnMut` trait, but this closure only implements `FnOnce`
  --> src/main.rs:25:13
   |
25 |     let f = ||drop(stuff);
   |             ^^^^^^^-----^
   |             |      |
   |             |      closure is `FnOnce` because it moves the variable `stuff` out of its environment
   |             this closure implements `FnOnce`, not `FnMut`
26 |     let g = Wrapper(f);
27 |     g();
   |     --- the requirement to implement `FnMut` derives from here

For more information about this error, try `rustc --explain E0525`.

From my understanding, the error message kind of makes sense. f indeed doesn't implement FnMut, so g doesn't either. However, g still implements FnOnce, which can be used here. It seems that the existence of FnMut implementation makes the compiler blind to the FnOnce implementation.

Similar thing can happen when both FnMut and Fn implementation exists but Fn is not implemented due to unsatisfied trait bound.

Meta

rustc --version --verbose:

1.57.0-nightly

(2021-09-15 2c7bc5e33c25e29058cb)

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory: This is a bug.F-unboxed_closures`#![feature(unboxed_closures)]`T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.requires-nightlyThis issue requires a nightly compiler in some way.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions