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

Misleading compiler suggestion when trying to match NonZero type #85049

Closed
baumanj opened this issue May 7, 2021 · 2 comments
Closed

Misleading compiler suggestion when trying to match NonZero type #85049

baumanj opened this issue May 7, 2021 · 2 comments
Labels
C-bug Category: This is a bug.

Comments

@baumanj
Copy link

baumanj commented May 7, 2021

I tried this code (playground link):

    let n = std::num::NonZeroU32::new(1).unwrap();
    match n {
        std::num::NonZeroU32(i) => {},
    }

I expected this to work.

Instead, this happened:

error[E0532]: expected tuple struct or tuple variant, found struct `std::num::NonZeroU32`
   --> src/lib.rs:4:9
    |
4   |           std::num::NonZeroU32(i) => {},
    |           ^^^^^^^^^^^^^^^^^^^^^^^ help: use struct pattern syntax instead: `std::num::NonZeroU32 { 0 }

And trying that (playground link):

error[E0769]: tuple variant `std::num::NonZeroU32` written as struct variant
 --> src/lib.rs:4:9
  |
4 |         std::num::NonZeroU32 { 0 } => {},
  |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
help: use the tuple variant pattern syntax instead
  |
4 |         std::num::NonZeroU32(0) => {},
  |                             ^^^

Results are the same in beta and nightly.

I recognize the real issue here is that the field of the NonZero newtype structs is private, but the error message could be better.

As an aside, it would be nice to be able to do this matching. In the end I resorted to

        match std::num::NonZeroU32::new(1).unwrap().get() {
            0 => unreachable!(),
            1 => Ok(n),
            d => {}
        }

which can't be compile-time verified

@baumanj baumanj added the C-bug Category: This is a bug. label May 7, 2021
@leonardo-m
Copy link

Rust language needs a well implemented value range analysis.

@luqmana
Copy link
Member

luqmana commented May 8, 2021

Dupe of #78708.

@luqmana luqmana closed this as completed May 8, 2021
GuillaumeGomez added a commit to GuillaumeGomez/rust that referenced this issue May 13, 2021
Fix diagnostic for cross crate private tuple struct constructors

Fixes rust-lang#78708.

There was already some limited support for certain cross-crate scenarios but that didn't handle a tuple struct rexported from an inner module for example (e.g. the NonZero* types as seen in rust-lang#85049).

```Rust
➜  cat bug.rs
fn main() {
    let _x = std::num::NonZeroU32(12);
    let n = std::num::NonZeroU32::new(1).unwrap();
    match n {
        std::num::NonZeroU32(i) => {},
    }
}
```

**Before:**
<details>

```Rust
➜  rustc +nightly bug.rs
error[E0423]: expected function, tuple struct or tuple variant, found struct `std::num::NonZeroU32`
   --> bug.rs:2:14
    |
2   |       let _x = std::num::NonZeroU32(12);
    |                ^^^^^^^^^^^^^^^^^^^^^^^^ help: use struct literal syntax instead: `std::num::NonZeroU32 { 0: val }`
    |
   ::: /home/luqman/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/num/nonzero.rs:148:1
[snip]
error[E0532]: expected tuple struct or tuple variant, found struct `std::num::NonZeroU32`
   --> bug.rs:5:9
    |
5   |           std::num::NonZeroU32(i) => {},
    |           ^^^^^^^^^^^^^^^^^^^^^^^ help: use struct pattern syntax instead: `std::num::NonZeroU32 { 0 }`
    |
   ::: /home/luqman/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/num/nonzero.rs:148:1
[snip]

error: aborting due to 2 previous errors

Some errors have detailed explanations: E0423, E0532.
For more information about an error, try `rustc --explain E0423`.
```
</details>

**After:**
<details>

```Rust
➜  /rust/build/x86_64-unknown-linux-gnu/stage1/bin/rustc bug.rs
error[E0423]: cannot initialize a tuple struct which contains private fields
   --> bug.rs:2:14
    |
2   |     let _x = std::num::NonZeroU32(12);
    |              ^^^^^^^^^^^^^^^^^^^^
    |
note: constructor is not visible here due to private fields
   --> /rust/library/core/src/num/nonzero.rs:148:1
[snip]
error[E0532]: cannot match against a tuple struct which contains private fields
 --> bug.rs:5:9
  |
5 |         std::num::NonZeroU32(i) => {},
  |         ^^^^^^^^^^^^^^^^^^^^
  |
note: constructor is not visible here due to private fields
 --> bug.rs:5:30
  |
5 |         std::num::NonZeroU32(i) => {},
  |                              ^ private field

error: aborting due to 2 previous errors

Some errors have detailed explanations: E0423, E0532.
For more information about an error, try `rustc --explain E0423`.
```
</details>

One question is if we should only collect the needed info for the cross-crate case after encountering an error instead of always doing it. Perf run perhaps to gauge the impact.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: This is a bug.
Projects
None yet
Development

No branches or pull requests

3 participants