Skip to content
New issue

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

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

Already on GitHub? # 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.
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
A-diagnostics Area: Messages for errors, warnings, and lints
Projects
None yet
Development

No branches or pull requests

5 participants