Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot call by reference to &mut F: FnMut #112808

Open
AngelicosPhosphoros opened this issue Jun 19, 2023 · 2 comments
Open

Cannot call by reference to &mut F: FnMut #112808

AngelicosPhosphoros opened this issue Jun 19, 2023 · 2 comments
Labels
C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@AngelicosPhosphoros
Copy link
Contributor

I tried this code:

fn call_by_ref<F, A0, A1>(mut f: F, arg0: A0, arg1: A1)
where
    A0: Sized,
    A1: Sized,
    for<'w> &'w mut F: FnMut(A0, A1),
{
    // This doesn't work.
    (&mut f)(arg0, arg1);
}

// Workaround
fn call_by_ref_and_hack<F, A0, A1>(mut f: F, arg0: A0, arg1: A1)
where
    A0: Sized,
    A1: Sized,
    for<'w> &'w mut F: FnMut(A0, A1),
{
    fn call_once<B0, B1>(f: impl FnOnce(B0, B1), arg0: B0, arg1: B1){
        f(arg0, arg1)
    }
    // This works
    call_once(&mut f, arg0, arg1);
}

I expected to see this happen: Both functions should compile and work.

Instead, this happened: Only version with inner function hack works.

Meta

rustc --version --verbose:

rustc 1.70.0 (90c541806 2023-05-31)

AFAIK, it never worked.

@AngelicosPhosphoros AngelicosPhosphoros added the C-bug Category: This is a bug. label Jun 19, 2023
@compiler-errors
Copy link
Member

compiler-errors commented Jun 19, 2023

Pretty sure that it's due to this hack 😓

// Hack: we know that there are traits implementing Fn for &F
// where F:Fn and so forth. In the particular case of types
// like `f: &mut FnMut()`, if there is a call `f()`, we would
// normally translate to `FnMut::call_mut(&mut f, ())`, but
// that winds up potentially requiring the user to mark their
// variable as `mut` which feels unnecessary and unexpected.
//
// fn foo(f: &mut impl FnMut()) { f() }
// ^ without this hack `f` would have to be declared as mutable
//
// The simplest fix by far is to just ignore this case and deref again,
// so we wind up with `FnMut::call_mut(&mut *f, ())`.
ty::Ref(..) if autoderef.step_count() == 0 => {
return None;
}

We really should be re-trying that branch if the other autoderef steps fail.

while result.is_none() && autoderef.next().is_some() {
result = self.try_overloaded_call_step(call_expr, callee_expr, arg_exprs, &autoderef);
}

@AngelicosPhosphoros
Copy link
Contributor Author

AngelicosPhosphoros commented Jun 21, 2023

Another workaround, probably more effecient:

fn call_by_anonymising<F, A0, A1>(mut f: F, arg0: A0, arg1: A1)
where
    A0: Sized,
    A1: Sized,
    for<'w> &'w mut F: FnMut(A0, A1),
{
    #[inlne]
    fn anonymise<B0, B1>(f: impl FnOnce(B0, B1))->impl FnOnce(B0, B1){
        f
    }
    // This works
    anonymise(&mut f)(arg0, arg1);
}

godbolt link

@ChrisDenton ChrisDenton added the needs-triage-legacy Old issue that were never triaged. Remove this label once the issue has been sufficiently triaged. label Jul 16, 2023
@Enselic Enselic added T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. and removed needs-triage-legacy Old issue that were never triaged. Remove this label once the issue has been sufficiently triaged. labels Jul 30, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

4 participants