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

Helpful error message when confusing a field with a method #2392

Closed
catamorphism opened this issue May 17, 2012 · 8 comments · Fixed by #26305
Closed

Helpful error message when confusing a field with a method #2392

catamorphism opened this issue May 17, 2012 · 8 comments · Fixed by #26305
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-typesystem Area: The type system E-easy Call for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue. P-low Low priority

Comments

@catamorphism
Copy link
Contributor

I forget if there's already a bug on this, but it would be nice if, when you wrote A.B and A doesn't have a field named B, but does have a nullary method named B, the compiler gave a hint like "did you mean to write A.B()?" It could also do vice versa (if you write A.B()andAis a class with fieldB, it could ask "did you meanA.B```?)

I ran into this in trans, where I have frequently written bcx.ccx instead of bcx.ccx().

@catamorphism
Copy link
Contributor Author

Test:

struct Cat {
    x: int
}

trait Meow {
    fn mew();
}

impl Cat: Meow {
    fn mew() {}
}

fn main() {
    let kitty = Cat { x:5 };
    assert kitty.mew == 1;
}

The error message is better now than it was:

/Users/tchevalier/rust/src/test/compile-fail/issue-2392.rs:15:11: 15:20 error: attempted to take value of method (try writing an anonymous function)
/Users/tchevalier/rust/src/test/compile-fail/issue-2392.rs:15     assert kitty.mew == 1;

in that it suggests there is a method named mew. But it could still be improved. (The intention may not have been to take the method's value; it seems more likely that the programmer thought it wasn't a method at all.)

@catamorphism
Copy link
Contributor Author

My previous comment still holds. It would be great if you would see the "try writing an anonymous function" hint for something like f(kitty.mew, xs) and instead see a "did you mean to write kitty.mew()?" in situations like this one.

@bblum
Copy link
Contributor

bblum commented Jul 3, 2013

I'd also like to see one when trying to call a function-typed struct field:

struct Foo {
    f: ~fn(),
}
fn foo(f: Foo) {
    f.f();
}
fn main() {}

emits error: type Foodoes not implement any method in scope namedf``.

It'd be nice if it tried to see if it could auto-deref to a struct field, and if so, say to use a struct field as a function, write (f.f)()``.

@pnkfelix
Copy link
Member

pnkfelix commented Jan 9, 2014

A nice idea. Assigning P-low.

@vks
Copy link
Contributor

vks commented Aug 29, 2014

Currently

struct Cat {
    x: int
}

trait Meow {
    fn mew(&self) -> int;
}

impl Meow for Cat {
    fn mew(&self) -> int {
        self.x
    }
}

fn main() {
    let kitty = Cat { x:5 };
    assert!(kitty.mew == 5);
}

gives

<anon>:17:19: 17:22 error: attempted to take value of method `mew` on type `Cat`
<anon>:17     assert!(kitty.mew == 5);
                            ^~~
<anon>:17:19: 17:22 note: maybe a missing `()` to call it? If not, try an anonymous function.
<anon>:17     assert!(kitty.mew == 5);
                            ^~~

which is pretty close to the proposed behavior.

Replacing the main wih

fn main() {
    let kitty = Cat { x:5 };
    assert!(kitty.x() == 5);
}

yields the same as before (i.e. does not suggest removing the ()):

<anon>:17:19: 17:22 error: type `Cat` does not implement any method in scope named `x`
<anon>:17     assert!(kitty.x() == 5);
                            ^~~

@huonw
Copy link
Member

huonw commented Mar 2, 2015

Updated the example @vks gives:

struct Cat {
    x: i32
}

trait Meow {
    fn mew(&self) -> i32;
}

impl Meow for Cat {
    fn mew(&self) -> i32 {
        self.x
    }
}

fn main() {
    let kitty = Cat { x:5 };
    assert!(kitty.x() == 5);
}

which now prints

<anon>:17:19: 17:22 error: type `Cat` does not implement any method in scope named `x`
<anon>:17     assert!(kitty.x() == 5);
                            ^~~
<anon>:17:19: 17:22 note: use `(s.x)(...)` if you meant to call the function stored in the `x` field
<anon>:17     assert!(kitty.x() == 5);
                            ^~~

It's nice that the note is there, but the text is suboptimal: kitty.x isn't a function.

@Nashenas88
Copy link
Contributor

I'm working on a fix for this, but I'm struggling with the final portion. With this code:

struct Cat<F> where F: FnMut() -> u32 {
    func: F,
    x: i32
}

trait Meow {
    fn mew(&self) -> i32;
}

impl Meow for Cat {
    fn mew(&self) -> i32 {
        self.x
    }
}

fn main() {
    let kitty = Cat { func: || 5, x: 5 };
    assert!(kitty.x() == 5);
    let x = kitty.func();
    assert_eq!(x, 5);
}

I get the output:

<anon>:18:19: 18:22 error: type `Cat` does not implement any method in scope named `x`
<anon>:18     assert!(kitty.x() == 5);
                            ^~~
<anon>:18:19: 18:22 note: did you mean to write `Cat.x`?
<anon>:18     assert!(kitty.x() == 5);
                            ^~~
<anon>:19:19: 19:25 error: type `Cat` does not implement any method in scope named `func`
<anon>:19     let x = kitty.func();
                            ^~~~~~
<anon>:19:19: 19:25 note: use `(Cat.func)(...)` if you meant to call the function stored in the `func` field
<anon>:19     let x = kitty.func();
                            ^~~~~~

My current changes are here. I'm not sure if it's possible to have the output say "kitty.func" and "kitty.x" with the input to the report_error function. Any ideas? Or should I just keep the message in the same format as it is now and output "s.func" and "did you mean to write s.x?"?

Edit:

Ideally, I would like to output:

<anon>:18:19: 18:22 error: type `Cat` does not implement any method in scope named `x`
<anon>:18     assert!(kitty.x() == 5);
                            ^~~
<anon>:18:19: 18:22 note: did you mean to write `kitty.x`?
<anon>:18     assert!(kitty.x() == 5);
                            ^~~
<anon>:19:19: 19:25 error: type `Cat` does not implement any method in scope named `func`
<anon>:19     let x = kitty.func();
                            ^~~~~~
<anon>:19:19: 19:25 note: use `(kitty.func)(...)` if you meant to call the function stored in the `func` field
<anon>:19     let x = kitty.func();
                            ^~~~~~

I'm wondering if that's at all possible, especially because instead of kitty, there might be an expression.

@Nashenas88
Copy link
Contributor

I got around that error message. Now I'm making sure the previous (kitty.func)(...) message is displayed under the proper circumstances.

Nashenas88 added a commit to Nashenas88/rust that referenced this issue Jun 20, 2015
bors added a commit that referenced this issue Jun 20, 2015
This fixes #2392

I'd like to thank @eddyb for helping me on this one! I wouldn't have gotten the complicated FnOnce check done without his help.
bors added a commit to rust-lang-ci/rust that referenced this issue Sep 22, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-typesystem Area: The type system E-easy Call for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue. P-low Low priority
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants