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

Implementing Fn<Args, R> for multiple Args results in confusing error #18952

Closed
tomjakubowski opened this issue Nov 14, 2014 · 7 comments
Closed
Labels
A-closures Area: closures (`|args| { .. }`) A-diagnostics Area: Messages for errors, warnings, and lints C-enhancement Category: An issue proposing an enhancement or a PR with one.

Comments

@tomjakubowski
Copy link
Contributor

It may be that overloaded calls aren't meant to be abused this way; even if that's the case I think the error message (at least the second one) could be improved:

#![feature(unboxed_closures)]

use std::ops::Fn;

struct Foo;

impl Fn<(isize, isize), ()> for Foo {
    extern "rust-call" fn call(&self, args: (isize, isize)) {
        println!("{:?}", args);
    }
}

impl Fn<(isize, isize, isize), ()> for Foo {
    extern "rust-call" fn call(&self, args: (isize, isize, isize)) {
        println!("{:?}", args);
    }
}


fn main() {
    let foo = Foo;
    foo(1, 1);
}
<anon>:22:5: 22:14 error: the type of this value must be known in this context
<anon>:22     foo(1, 1);
              ^~~~~~~~~
<anon>:22:5: 22:14 error: cannot use call notation; the first type parameter for the function trait is neither a tuple nor unit [E0059]
<anon>:22     foo(1, 1);
              ^~~~~~~~~

edit: updated source for rust changes on 2014-12-03
edit: another update 2015-01-20

@tomjakubowski
Copy link
Contributor Author

I should note the same happens for overloading on the return type:

#![feature(unboxed_closures)]
use std::ops::Fn;
struct Foo;

impl Fn(i32, i32) for Foo {
    extern "rust-call" fn call(&self, args: (i32, i32)) {
        println!("{:?}", args);
    }
}

impl Fn(i32, i32) -> i32 for Foo {
    extern "rust-call" fn call(&self, args: (i32, i32)) -> i32 {
        println!("{:?}", args);
        0
    }
}

fn main() {
    let foo = Foo;
    let x: i32 = foo(1, 1);
}

@steveklabnik steveklabnik added the A-closures Area: closures (`|args| { .. }`) label Jan 29, 2015
@steveklabnik
Copy link
Member

steveklabnik commented Mar 4, 2016

Triage: same error today. Here's the updated code:

#![feature(unboxed_closures)]

use std::ops::Fn;

struct Foo;

impl Fn<(isize, isize)> for Foo {
    extern "rust-call" fn call(&self, args: (isize, isize)) -> Self::Output {
        println!("{:?}", args);
    }
}

impl FnMut<(isize, isize)> for Foo {
    extern "rust-call" fn call_mut(&mut self, args: (isize, isize)) -> Self::Output {
        println!("{:?}", args);
    }
}

impl FnOnce<(isize, isize)> for Foo {
    type Output = ();
    extern "rust-call" fn call_once(self, args: (isize, isize)) -> Self::Output {
        println!("{:?}", args);
    }
}

impl Fn<(isize, isize, isize)> for Foo {
    extern "rust-call" fn call(&self, args: (isize, isize, isize)) -> Self::Output {
        println!("{:?}", args);
    }
}

impl FnMut<(isize, isize, isize)> for Foo {
    extern "rust-call" fn call_mut(&mut self, args: (isize, isize, isize)) -> Self::Output {
        println!("{:?}", args);
    }
}
impl FnOnce<(isize, isize, isize)> for Foo {
    type Output = ();
    extern "rust-call" fn call_once(self, args: (isize, isize, isize)) -> Self::Output {
        println!("{:?}", args);
    }
}

fn main() {
    let foo = Foo;
    foo(1, 1);
}

@Mark-Simulacrum Mark-Simulacrum added A-diagnostics Area: Messages for errors, warnings, and lints C-enhancement Category: An issue proposing an enhancement or a PR with one. labels Jul 22, 2017
@cyplo
Copy link
Contributor

cyplo commented Aug 23, 2017

Still same error on rustc 1.21.0-nightly (469a6f9 2017-08-22)

@alexreg
Copy link
Contributor

alexreg commented Aug 20, 2018

Is this still occurring?

@cyplo
Copy link
Contributor

cyplo commented Aug 20, 2018

Looking at the link provided by Steve - it seems it's still failing on the nightly on playground (https://play.rust-lang.org/?gist=fe78a973c074edba7b422252bdf40bf1&version=nightly)
The error messages are slightly but not largely different now.

@alexreg
Copy link
Contributor

alexreg commented Aug 20, 2018

I agree, the error message is still pretty confusing. Ideally, the error would be at the point of defining the second impl Fn<...> for the same type.

Mark-Simulacrum added a commit to Mark-Simulacrum/rust that referenced this issue Jan 3, 2019
Allow to dispatch fn traits depending on number of parameters

Hello,

By following @eddyb's advise on issue rust-lang#45510, I managed to have the snippets of code in rust-lang#45510 and rust-lang#18952 passing without breaking older diagnostics.

EDIT: the codegen tests breakage I experienced is due to the poor quality of my laptop.

If any kind reviewer has any advice, you are very welcome.
bors added a commit that referenced this issue Jan 4, 2019
Allow to dispatch fn traits depending on number of parameters

Hello,

By following @eddyb's advise on issue #45510, I managed to have the snippets of code in #45510 and #18952 passing without breaking older diagnostics.

EDIT: the codegen tests breakage I experienced is due to the poor quality of my laptop.

If any kind reviewer has any advice, you are very welcome.
@estebank
Copy link
Contributor

This case now compiles successfully, and most of the errors that you would encounter by forgetting to use the correct impl are mostly reasonable:

error[E0046]: not all trait items implemented, missing: `Output`
 --> src/main.rs:8:1
  |
8 | impl FnOnce<(isize, isize)> for Foo {
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `Output` in implementation
  |
  = note: `Output` from trait: `type Output;`
error[E0277]: expected a `std::ops::FnMut<(isize, isize)>` closure, found `Foo`
 --> src/main.rs:8:6
  |
8 | impl Fn<(isize, isize)> for Foo {
  |      ^^^^^^^^^^^^^^^^^^ expected an `FnMut<(isize, isize)>` closure, found `Foo`
  |
  = help: the trait `std::ops::FnMut<(isize, isize)>` is not implemented for `Foo`
error[E0107]: wrong number of type arguments: expected 1, found 2
 --> src/main.rs:8:16
  |
8 | impl Fn<isize, isize> for Foo {
  |                ^^^^^ unexpected type argument

error[E0107]: wrong number of type arguments: expected 1, found 2
  --> src/main.rs:13:19
   |
13 | impl FnMut<isize, isize> for Foo {
   |                   ^^^^^ unexpected type argument

error[E0107]: wrong number of type arguments: expected 1, found 2
  --> src/main.rs:18:20
   |
18 | impl FnOnce<isize, isize> for Foo {
   |                    ^^^^^ unexpected type argument

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-closures Area: closures (`|args| { .. }`) A-diagnostics Area: Messages for errors, warnings, and lints C-enhancement Category: An issue proposing an enhancement or a PR with one.
Projects
None yet
Development

No branches or pull requests

6 participants