Skip to content

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

Closed
@catamorphism

Description

@catamorphism
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().

Activity

catamorphism

catamorphism commented on Nov 8, 2012

@catamorphism
ContributorAuthor

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

catamorphism commented on Jan 20, 2013

@catamorphism
ContributorAuthor

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

bblum commented on Jul 3, 2013

@bblum
Contributor

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

pnkfelix commented on Jan 9, 2014

@pnkfelix
Member

A nice idea. Assigning P-low.

vks

vks commented on Aug 29, 2014

@vks
Contributor

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

huonw commented on Mar 2, 2015

@huonw
Member

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

Nashenas88 commented on Jun 13, 2015

@Nashenas88
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

Nashenas88 commented on Jun 14, 2015

@Nashenas88
Contributor

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

added a commit that references this issue on Jun 20, 2015

Auto merge of #26305 - Nashenas88:field-method-message-2392, r=eddyb

7d4d77f

6 remaining items

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-diagnosticsArea: Messages for errors, warnings, and lintsA-type-systemArea: Type systemE-easyCall for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue.P-lowLow priority

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      Participants

      @vks@pnkfelix@catamorphism@huonw@Nashenas88

      Issue actions

        Helpful error message when confusing a field with a method · Issue #2392 · rust-lang/rust