How does Rust control scope and privacy? Does it automatically infer?

Viewed 66

I have code like this:

mod _mod1 {
    struct _A {}

    pub(in crate::_mod1) mod _mod2 {
        use super::_A;
        pub struct _B {}

        impl _B {
            pub fn _test(_a: _A) {}
        }
    }
}

And then I run cargo check, it tells me that "private type _A in public interface".

error[E0446]: private type `_A` in public interface
 --> src/main.rs:9:13
  |
2 |     struct _A {}
  |     --------- `_A` declared as private
...
9 |             pub fn _test(_a: _A) {}
  |             ^^^^^^^^^^^^^^^^^^^^ can't leak private type

For more information about this error, try `rustc --explain E0446`.
error: could not compile `mytest` due to previous error

In my opinion, in this code, although _test method is pub, mod _mod2 is pub(in crate::_mod1). struct _B and _test method can only be accessed in mod _mod1, which meets A's access requirements. Does Rust infer control scope and privacy?

1 Answers

Rust does not considers the privacy of the module when calculating this error, and for a good reason.

You could have reexported _B publicly in _mod1:

mod _mod1 {
    struct _A {}

    pub(in crate::_mod1) mod _mod2 {
        use super::_A;
        pub struct _B {}

        impl _B {
            pub fn _test(_a: _A) {}
        }
    }

    pub use _mod2::B;
}

Now the code that has access to _mod1 has access to _B::_test(), too, and thus has access to _mod1::_A although it shouldn't as it is private.

In theory, maybe Rust could mitigate this risk by analyzing the whole module and detecting if the item is reexported, but in practice, this is both too expensive and unintuitive, and can cause unexpected failures when unrelated code changes (imagine a glob import that doesn't even mention the type).

So Rust only checks the privacy of the item itself.

Related