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

Trying to access public function with same name as private field gives confusing error #26472

Closed
stephenmw opened this issue Jun 21, 2015 · 9 comments
Labels
A-diagnostics Area: Messages for errors, warnings, and lints

Comments

@stephenmw
Copy link

When trying to access the len of a Vec I forgot the parens. This led to an error message about using a private field which confused me. (Thanks to the IRC for helping me find the problem!)

Code:

use std::vec::Vec;

fn main() {
    let xs: Vec<i32> = Vec::new();
    xs.len;
}

Error:

baderror.rs:5:2: 5:8 error: field `len` of struct `collections::vec::Vec` is private
baderror.rs:5   xs.len;
                ^~~~~~
error: aborting due to previous error
Illegal instruction
@stephenmw
Copy link
Author

@aturon

@Ms2ger
Copy link
Contributor

Ms2ger commented Jun 21, 2015

CC me

@Ms2ger
Copy link
Contributor

Ms2ger commented Jun 22, 2015

Maybe fixed by #26305?

@steveklabnik
Copy link
Member

It is not, @Ms2ger , I can confirm same error with rustc 1.2.0-nightly (cffaf0e7a 2015-06-23)

@steveklabnik steveklabnik added the A-diagnostics Area: Messages for errors, warnings, and lints label Jun 23, 2015
@Manishearth
Copy link
Member

cc @Nashenas88 want to try looking into this?

@Nashenas88
Copy link
Contributor

@Manishearth, that seems tricky. The error is correct, but maybe we could add a useful note here. I'll take a look later today.

@Nashenas88
Copy link
Contributor

This looks fixable, though I think I've also found a bug in #26305. I could potentially be recommending private functions there. A common solution could fix both of these issues, but the code for this error is in librustc_privacy, and the code for #26305 is in librustc_typeck. Where should I put the fix so it's accessible by both folders?

@Nashenas88
Copy link
Contributor

I was wrong, it's not so simple. Something that didn't pop into my head until later is the fact that Rust allows a struct field and a struct implementation's function to have the same name. Most languages don't allow this. I thought the code between the two could be shared, but the use cases are very different from the compiler's perspective.

I played around with the following on the playground to see what the existing behavior is:

#![feature(core, unboxed_closures)]
mod inner {
    pub struct Dog {
        pub x: usize,
        pub c: Barking,
        d: Barking,
    }

    impl Dog {
        pub fn new() -> Dog {
            Dog {
                x: 5,
                c: Barking,
                d: Barking,
            }
        }

        pub fn d() -> usize {
            3
        }
    }

    pub struct Barking;
    impl Barking {
        pub fn woof(&self) -> usize {
            3
        }
    }

    impl Fn<()> for Barking {
        extern "rust-call" fn call(&self, _: ()) -> usize {
            self.woof()
        }
    }

    impl FnMut<()> for Barking {   
        extern "rust-call" fn call_mut(&mut self, _: ()) -> usize {
            self.woof()
        }
    }

    impl FnOnce<()> for Barking {
        type Output = usize;
        extern "rust-call" fn call_once(self, _: ()) -> usize {
            self.woof()
        }
    }
}

fn main() {
    let dog = inner::Dog::new();
    let _ = dog.x();
    let _ = dog.c();
    let _ = (dog.c)();
    let _ = dog.d();
    let _ = (dog.d)();
}

This gives the following output on nightly:

<anon>:52:17: 52:20 error: no method named `x` found for type `inner::Dog` in the current scope
<anon>:52     let _ = dog.x();
                          ^~~
<anon>:52:17: 52:20 note: did you mean to write `dog.x`?
<anon>:52     let _ = dog.x();
                          ^~~
<anon>:53:17: 53:20 error: no method named `c` found for type `inner::Dog` in the current scope
<anon>:53     let _ = dog.c();
                          ^~~
<anon>:53:17: 53:20 note: use `(dog.c)(...)` if you meant to call the function stored in the `c` field
<anon>:53     let _ = dog.c();
                          ^~~
<anon>:55:17: 55:20 error: no method named `d` found for type `inner::Dog` in the current scope
<anon>:55     let _ = dog.d();
                          ^~~
<anon>:55:17: 55:20 note: use `(dog.d)(...)` if you meant to call the function stored in the `d` field
<anon>:55     let _ = dog.d();
                          ^~~
<anon>:55:17: 55:20 note: found defined static methods, maybe a `self` is missing?
<anon>:18:9: 20:10 note: candidate #1 is defined in an impl for the type `inner::Dog`
<anon>:18         pub fn d() -> usize {
<anon>:19             3
<anon>:20         }
error: aborting due to 3 previous errors
playpen: application terminated with error code 101

(playground here)

If I add &self as a param to the d fn, the the last error goes away. If I then comment out the lines like so:

fn main() {
    let dog = inner::Dog::new();
    // let _ = dog.x();
    // let _ = dog.c();
    // let _ = (dog.c)();
    let _ = dog.d();
    let _ = (dog.d)();
}

I get this error:

<anon>:56:14: 56:19 error: field `d` of struct `inner::Dog` is private
<anon>:56     let _ = (dog.d)();
                       ^~~~~
error: aborting due to previous error
playpen: application terminated with error code 101

So the private errors are checked on a separate pass.

I'd like to use the same style of note message as the static methods note. I just need to see how complicated it will be to get the type's function list from librustc_privacy

@Nashenas88
Copy link
Contributor

FYI: I haven't been had the time to work on this issue as thoroughly as I'd have liked to. Anyone is free to pick this up.

birkenfeld added a commit to birkenfeld/rust that referenced this issue May 2, 2016
For example, `Vec::len` is both a field and a method, and usually
encountering `vec.len` just means that the parens were forgotten.

Fixes: rust-lang#26472
steveklabnik added a commit to steveklabnik/rust that referenced this issue May 2, 2016
typeck: if a private field exists, also check for a public method

For example, `Vec::len` is both a field and a method, and usually encountering `vec.len` just means that the parens were forgotten.

Fixes: rust-lang#26472

NOTE: I added the parameter `allow_private` to `method::exists` since I don't want to suggest inaccessible methods. For the second case, where only the method exists, I think it would make sense to set it to `false` as well, but I wanted to preserve compatibility for this case.
steveklabnik added a commit to steveklabnik/rust that referenced this issue May 5, 2016
typeck: if a private field exists, also check for a public method

For example, `Vec::len` is both a field and a method, and usually encountering `vec.len` just means that the parens were forgotten.

Fixes: rust-lang#26472

NOTE: I added the parameter `allow_private` to `method::exists` since I don't want to suggest inaccessible methods. For the second case, where only the method exists, I think it would make sense to set it to `false` as well, but I wanted to preserve compatibility for this case.
birkenfeld added a commit to birkenfeld/rust that referenced this issue May 10, 2016
For example, `Vec::len` is both a field and a method, and usually
encountering `vec.len` just means that the parens were forgotten.

Fixes: rust-lang#26472
steveklabnik added a commit to steveklabnik/rust that referenced this issue May 10, 2016
typeck: if a private field exists, also check for a public method

For example, `Vec::len` is both a field and a method, and usually encountering `vec.len` just means that the parens were forgotten.

Fixes: rust-lang#26472

NOTE: I added the parameter `allow_private` to `method::exists` since I don't want to suggest inaccessible methods. For the second case, where only the method exists, I think it would make sense to set it to `false` as well, but I wanted to preserve compatibility for this case.
steveklabnik added a commit to steveklabnik/rust that referenced this issue May 10, 2016
typeck: if a private field exists, also check for a public method

For example, `Vec::len` is both a field and a method, and usually encountering `vec.len` just means that the parens were forgotten.

Fixes: rust-lang#26472

NOTE: I added the parameter `allow_private` to `method::exists` since I don't want to suggest inaccessible methods. For the second case, where only the method exists, I think it would make sense to set it to `false` as well, but I wanted to preserve compatibility for this case.
birkenfeld added a commit to birkenfeld/rust that referenced this issue May 12, 2016
For example, `Vec::len` is both a field and a method, and usually
encountering `vec.len` just means that the parens were forgotten.

Fixes: rust-lang#26472
eddyb added a commit to eddyb/rust that referenced this issue May 12, 2016
typeck: if a private field exists, also check for a public method

For example, `Vec::len` is both a field and a method, and usually encountering `vec.len` just means that the parens were forgotten.

Fixes: rust-lang#26472

NOTE: I added the parameter `allow_private` to `method::exists` since I don't want to suggest inaccessible methods. For the second case, where only the method exists, I think it would make sense to set it to `false` as well, but I wanted to preserve compatibility for this case.
eddyb added a commit to eddyb/rust that referenced this issue May 13, 2016
typeck: if a private field exists, also check for a public method

For example, `Vec::len` is both a field and a method, and usually encountering `vec.len` just means that the parens were forgotten.

Fixes: rust-lang#26472

NOTE: I added the parameter `allow_private` to `method::exists` since I don't want to suggest inaccessible methods. For the second case, where only the method exists, I think it would make sense to set it to `false` as well, but I wanted to preserve compatibility for this case.
sanxiyn added a commit to sanxiyn/rust that referenced this issue May 14, 2016
typeck: if a private field exists, also check for a public method

For example, `Vec::len` is both a field and a method, and usually encountering `vec.len` just means that the parens were forgotten.

Fixes: rust-lang#26472

NOTE: I added the parameter `allow_private` to `method::exists` since I don't want to suggest inaccessible methods. For the second case, where only the method exists, I think it would make sense to set it to `false` as well, but I wanted to preserve compatibility for this case.
Manishearth added a commit to Manishearth/rust that referenced this issue May 15, 2016
typeck: if a private field exists, also check for a public method

For example, `Vec::len` is both a field and a method, and usually encountering `vec.len` just means that the parens were forgotten.

Fixes: rust-lang#26472

NOTE: I added the parameter `allow_private` to `method::exists` since I don't want to suggest inaccessible methods. For the second case, where only the method exists, I think it would make sense to set it to `false` as well, but I wanted to preserve compatibility for this case.
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
Projects
None yet
Development

No branches or pull requests

5 participants