[lang-team-minutes] private-in-public rules

@nikomatsakis

what did you mean by "reexport checking in resolve"

Checks preventing pub use Private;. They are performed early and work on "name level"/"path level" (as opposed to "type level") and prevent suddenly turning private items into public items by reexporting them. By checking types alone we cannot prevent leaking "frontend" entities like modules through reexports. (The exact rules implemented as part of RFC 1560 are slightly more complex than "pub use Private; is an error", because they need to work with pub(restricted), globs and imports in several namespaces).


I think that (as I explained in the internals thread) we do need some checking for associated types in impls, at least.

I don't think associated types need any special treatment (modulo linking, see below) because they are equivalent to impl Trait from privacy and stability point of view when used in generic context. Suppose we have a private associated type:

trait PubTrait {
    type A: Bounds;
}
impl PubTrait for PubType {
    type A = PrivType;
}

When this type is used in concrete, non-generic context

let a: PubType::A = ...;

we leak everything about PrivType - we can call its inherent methods, copy it several times if it's Copy, cast it to other implemented non-Bounds traits, transmute it to something, etc, etc, etc. The author of PrivType can't change anything about PrivType backward compatibly, because all the details of PrivType can be used by third parties. This is wrong, you can't name a type private if it has to adhere to such severe restrictions. That's why concrete, "normalizable" associated types need to be checked for privacy on use.

When the associated type A is used in generic context, like TypeParam::A it's equivalent to public anonymized type impl Bounds for users. impl Bounds is the only knowledge we have about PrivType when TypeParam is suddenly equal to PubType. The author of PrivType can change it in arbitrary ways and even completely purge it and provide some other implementation of his public contract impl PubTrait for PubType.


Link time visibility is very useful, but under-appreciated perspective on privacy issues. Here are some points.

  1. We want to minimize link time visibility of all crate symbols.
  2. Language privacy is the primary fuel for this minimization.
  3. Impls of public traits for private types is the tricky case.
  4. We want all the numerous #[derive(Clone, PartialEq, Debug, Hash)] impls for private types to be "internalized" and not to stick out from our crates.
  5. We still want impl Trait to work for private types at link time, so impls participating in impl Trait need to be "externalized".

The last point is relevant to private associated types in generic contexts as well, because they are so similar to impl Trait. If impls participating in Bounds for these associated types are "externalized" as if they participate in impl Bounds, then we are good and don't need any additional interface checks for associated types.