Skip to content

Unhelpful error message constructing re-exported tuple struct with private fields #66067

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

Open
mtrsl opened this issue Nov 3, 2019 · 7 comments
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-visibility Area: Visibility / privacy C-enhancement Category: An issue proposing an enhancement or a PR with one. D-confusing Diagnostics: Confusing error or lint that should be reworked. D-incorrect Diagnostics: A diagnostic that is giving misleading or incorrect information. D-papercut Diagnostics: An error or lint that needs small tweaks. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@mtrsl
Copy link
Contributor

mtrsl commented Nov 3, 2019

If a public tuple struct with private fields is declared in a public module, then instantiated elsewhere, the error message is helpful. For example, the code

// src/lib.rs
pub mod a {
    pub struct Triplet(usize, usize, f64);
}
// src/main.rs
use triplets::a::Triplet;

fn main() {
    let mut triplets = Vec::new();
    triplets.push(Triplet(0, 0, 1.0));
}

causes the compiler to give the following useful error message:

error[E0423]: expected function, tuple struct or tuple variant, found struct `Triplet`
 --> src/main.rs:5:19
  |
5 |     triplets.push(Triplet(0, 0, 1.0));
  |                   ^^^^^^^
  |                   |
  |                   constructor is not visible here due to private fields
  |                   help: a local variable with a similar name exists: `triplets`

error: aborting due to previous error

This tells us exactly what the problem is - that we cannot construct Triplet because its fields are private.

However, if the tuple struct is in a private module, but re-exported as public, the error message isn't helpful (it's even confusing). For example,

// src/lib.rs
mod a {
    pub struct Triplet(usize, usize, f64);
}
pub use a::Triplet;
// src/main.rs
use triplets::Triplet;

fn main() {
    let mut triplets = Vec::new();
    triplets.push(Triplet(0, 0, 1.0));
}

gives the compiler error

error[E0423]: expected function, tuple struct or tuple variant, found struct `Triplet`
 --> src/main.rs:5:19
  |
5 |     triplets.push(Triplet(0, 0, 1.0));
  |                   ^^^^^^^
  |                   |
  |                   did you mean `Triplet { /* fields */ }`?
  |                   help: a local variable with a similar name exists: `triplets`

error: aborting due to previous error

which confusingly suggests initialising the tuple with braces, instead of reporting that the fields are private.

Unsurprisingly, both versions work fine if the fields of Triplet are made public.

@mtrsl mtrsl changed the title Unhelpful error message with re-exported tuple struct with private fields Unhelpful error message constructing re-exported tuple struct with private fields Nov 3, 2019
@estebank estebank added A-diagnostics Area: Messages for errors, warnings, and lints A-visibility Area: Visibility / privacy D-papercut Diagnostics: An error or lint that needs small tweaks. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Nov 4, 2019
@estebank
Copy link
Contributor

estebank commented Jan 6, 2020

Current output:

error[E0423]: expected function, tuple struct or tuple variant, found struct `Triplet`
 --> src/main.rs:5:19
  |
5 |     triplets.push(Triplet(0, 0, 1.0));
  |                   ^^^^^^^
  |                   |
  |                   constructor is not visible here due to private fields
  |                   help: a local variable with a similar name exists: `triplets`

@JohnTitor JohnTitor added the C-enhancement Category: An issue proposing an enhancement or a PR with one. label Jan 12, 2020
@contrun
Copy link
Contributor

contrun commented Mar 11, 2020

@mtrsl
Copy link
Contributor Author

mtrsl commented Mar 19, 2020

This is not fixed for me on the latest nightly (2020-03-18). The bad error message doesn't seem to appear when the modules are declared and used in a single file, which is what the playground link by @contrun does.

@PitiBouchon
Copy link

PitiBouchon commented Nov 20, 2024

Simple reproducer :

pub use my_mod::MyStruct; // this pub use is causing the problem

mod my_mod {
    #[derive(Debug)]
    pub struct MyStruct(u32);

    mod my_sub_mod {
        use crate::MyStruct; // import the rexported struct

        fn my_func() {
            let s = MyStruct(42);
            println!("MyStruct: {:?}", s);
        }
    }
}

which when cargo build print :

error[E0423]: expected function, tuple struct or tuple variant, found struct `MyStruct`
  --> src/lib.rs:11:21
   |
11 |             let s = MyStruct(42);
   |                     ^^^^^^^^

For more information about this error, try `rustc --explain E0423`.

PS: this is another issue -> #133343

@estebank estebank added D-confusing Diagnostics: Confusing error or lint that should be reworked. D-incorrect Diagnostics: A diagnostic that is giving misleading or incorrect information. labels Nov 20, 2024
@n47h4n13l
Copy link

I just stumbled upon this, too.
The code PitiBouchon posted not only gives a confusing error, I would even expect it to not error at all!
Since the error refers to code in a submodule, it should be perfectly fine to use the constructor this way. For example for structs with 'normal' fields, it works perfectly.

@mtrsl
Copy link
Contributor Author

mtrsl commented Nov 22, 2024

Simple reproducer :

pub use my_mod::MyStruct; // this pub use is causing the problem

mod my_mod {
#[derive(Debug)]
pub struct MyStruct(u32);

mod my_sub_mod {
    use crate::MyStruct; // import the rexported struct

    fn my_func() {
        let s = MyStruct(42);
        println!("MyStruct: {:?}", s);
    }
}

}

which when cargo build print :

error[E0423]: expected function, tuple struct or tuple variant, found struct `MyStruct`
  --> src/lib.rs:11:21
   |
11 |             let s = MyStruct(42);
   |                     ^^^^^^^^

For more information about this error, try `rustc --explain E0423`.

I agree this is also confusing, but I'm not sure it's the same as the original bug. The original bug was about the error message not telling us about the private fields of the struct and instead suggesting the incorrect Triplet {...} for initialising the tuple struct.

I've just tested the original code (the second case in the first post - the first case already had a good error message) on the latest nightly, and it actually seems to be fixed now:

error[E0423]: cannot initialize a tuple struct which contains private fields
 --> src/main.rs:6:19
  |
6 |     triplets.push(Triplet(0, 0, 1.0));
  |                   ^^^^^^^ help: a local variable with a similar name exists: `triplets`
  |
note: constructor is not visible here due to private fields
 --> /home/mjr/Code/test/rust-66067/src/lib.rs:3:24
  |
3 |     pub struct Triplet(usize, usize, f64);
  |                        ^^^^^  ^^^^^  ^^^ private field
  |                        |      |
  |                        |      private field
  |                        private field

@PitiBouchon
Copy link

I've made another issue so -> #133343

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-visibility Area: Visibility / privacy C-enhancement Category: An issue proposing an enhancement or a PR with one. D-confusing Diagnostics: Confusing error or lint that should be reworked. D-incorrect Diagnostics: A diagnostic that is giving misleading or incorrect information. D-papercut Diagnostics: An error or lint that needs small tweaks. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

6 participants