Skip to content

Commit 2e88bc7

Browse files
committed
Amend RFC 48
1 parent 96fe95c commit 2e88bc7

File tree

1 file changed

+139
-109
lines changed

1 file changed

+139
-109
lines changed

active/0048-no-privates-in-public.md

Lines changed: 139 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ case), and this is the mechanism which should be used for it.
2727

2828
[questions]: https://github.com/rust-lang/rust/issues/10573
2929

30-
3130
## Examples of strangeness
3231

3332
(See also https://github.com/rust-lang/rust/issues/10573.)
@@ -61,7 +60,6 @@ questions can be deduced from them mechanically. But that doesn't mean it's a
6160
good idea to do so. If the results are bizarre, then our assumptions should be
6261
reconsidered. In these cases, it would be wiser to simply say, "don't do that".
6362

64-
6563
## Properties
6664

6765
By restricting public APIs to only mentioning public items, we can guarantee that:
@@ -247,6 +245,16 @@ gate has been removed, they will apply always.
247245
An item is considered to be publicly exposed by a module if it is declared `pub`
248246
by that module, or if it is re-exported using `pub use` by that module.
249247

248+
Items in a `impl` of a trait (not an inherent impl) are considered public
249+
if all of the following conditions are met:
250+
251+
* The trait being implemented is public.
252+
* All input types (currently, the self type) of the impl are public.
253+
* *Motivation:* If any of the input types or the trait is public, it
254+
should be impossible for an outside to access the items defined in
255+
the impl. They cannot name the types nor they can get direct access
256+
to a value of those types.
257+
250258
For items which are publicly exposed by a module, the rules are that:
251259

252260
* If it is a `static` declaration, items referred to in its type must be public.
@@ -263,160 +271,175 @@ For items which are publicly exposed by a module, the rules are that:
263271
* If it is a `trait` declaration, items referred to in its super-traits, in the
264272
trait bounds of its type parameters, and in the signatures of its methods
265273
(see `fn` case above) must be public.
266-
267-
274+
268275
## What does "public" mean?
269276

270-
An item `Item` referred to in the module `module` is considered to be public if:
271-
272-
* The qualified name used by `module` to refer to `Item`, when recursively
273-
resolved through `use` declarations back to the original declaration of
274-
`Item`, resolves along the way to at least one `pub` declaration, whether a
275-
`pub use` declaration or a `pub` original declaration; and
276-
277-
* For at least one of the above resolved-to `pub` declarations, all ancestor
278-
modules of the declaration, up to the deepest common ancestor module of the
279-
declaration with `module`, are `pub`.
280-
281-
In all other cases, an `Item` referred to in `module` is not considered to be
282-
public, or `module` itself cannot refer to `Item` and the distinction is
283-
irrelevant.
277+
An item is considered "public" if it is declared with the `pub` qualifier.
284278

285279
### Examples
286280

287-
In the following examples, the item `Item` referred to in the module `module`
288-
is considered to be public:
281+
Here are some examples to demonstrate the rules.
289282

290-
````
291-
pub mod module {
292-
pub struct Item { ... }
293-
}
294-
````
283+
#### Struct fields
295284

296285
````
297-
pub struct Item { ... }
298-
pub mod module {
299-
use Item;
286+
// A private struct may refer to any type in any field.
287+
struct Priv {
288+
a: Priv,
289+
b: Pub,
290+
pub c: Priv
300291
}
301-
````
302292
303-
````
304-
pub mod x {
305-
pub struct Item { ... }
293+
enum Vapor<A> { X, Y, Z } // Note that A is not used
294+
295+
// Public fields of a public struct may only refer to public types.
296+
pub struct Item {
297+
// Private field may reference a private type.
298+
a: Priv,
299+
300+
// Public field must refer to a public type.
301+
pub b: Pub,
302+
303+
// ERROR: Public field refers to a private type.
304+
pub c: Priv,
305+
306+
// ERROR: Public field refers to a private type.
307+
// For the purposes of this test, we do not descend into the type,
308+
// but merely consider the names that appear in type parameters
309+
// on the type, regardless of usage (or lack thereof) within the type
310+
// definition itself.
311+
pub d: Vapor<Priv>,
306312
}
307-
pub mod module {
308-
use x::Item;
309-
}
310-
````
311313
314+
pub struct Pub { ... }
312315
````
313-
pub mod module {
314-
pub mod x {
315-
pub struct Item { ... }
316-
}
317-
use self::x::Item;
316+
317+
#### Methods
318+
319+
```
320+
struct Priv { .. }
321+
pub struct Pub { .. }
322+
pub struct Foo { .. }
323+
324+
impl Foo {
325+
// Illegal: public method with argument of private type.
326+
pub fn foo(&self, p: Priv) { .. }
318327
}
319-
````
328+
```
320329

321-
````
322-
struct Item { ... }
323-
pub mod module {
324-
pub use Item;
330+
#### Trait bounds
331+
332+
```
333+
trait PrivTrait { ... }
334+
335+
// Error: type parameter on public item bounded by a private trait.
336+
pub struct Foo<X: PrivTrait> { ... }
337+
338+
// OK: type parameter on private item.
339+
struct Foo<X: PrivTrait> { ... }
340+
```
341+
342+
#### Trait definitions
343+
344+
```
345+
struct PrivStruct { ... }
346+
347+
pub trait PubTrait {
348+
// Error: private struct referenced from method in public trait
349+
fn method(x: PrivStruct) { ... }
325350
}
326-
````
327351
328-
````
329-
struct Foo { ... }
330-
pub use Item = Foo;
331-
pub mod module {
332-
use Item;
352+
trait PrivTrait {
353+
// OK: private struct referenced from method in private trait
354+
fn method(x: PrivStruct) { ... }
333355
}
334-
````
356+
```
335357

336-
````
337-
struct Foo { ... }
338-
pub use Bar = Foo;
339-
use Item = Bar;
340-
pub mod module {
341-
use Item;
358+
#### Implementations
359+
360+
To some extent, implementations are prevented from exposing private
361+
types because their types must match the trait. However, that is not
362+
true with generics.
363+
364+
```
365+
pub trait PubTrait<T> {
366+
fn method(t: T);
342367
}
343-
````
344368
345-
````
346-
struct Item { ... }
347-
pub mod x {
348-
pub use Item;
349-
pub mod y {
350-
use x::Item;
351-
pub mod module {
352-
use super::Item;
353-
}
369+
struct PubStruct { ... }
370+
371+
struct PrivStruct { ... }
372+
373+
impl PubTrait<PrivStruct> for PubStruct {
374+
// ^~~~~~~~~~ Error: Private type referenced from impl of
375+
// public trait on a public type. [Note: this is
376+
// an "associated type" here, not an input.]
377+
378+
fn method(t: PrivStruct) {
379+
// ^~~~~~~~~~ Error: Private type in method signature.
380+
//
381+
// Implementation note. It may not be a good idea to report
382+
// an error here; I think private types can only appear in
383+
// an impl by having an associated type bound to a private
384+
// type.
354385
}
355386
}
356-
````
387+
```
357388

358-
In the above examples, it is assumed that `module` will refer to `Item` as
359-
simply `Item`, but the same thing holds true if `module` refrains from importing
360-
`Item` explicitly with a private `use` declaration, and refers to it directly by
361-
qualifying it with a path instead.
389+
#### Type aliases
362390

391+
Note that the path to the public item does not have to be private.
363392

364-
In the below examples, the item `Item` referred to in the module `module` is
365-
*not* considered to be public:
366-
367-
````
368-
pub mod module {
369-
struct Item { ... }
393+
```
394+
mod impl {
395+
pub struct Foo { ... }
370396
}
371-
````
397+
pub type Bar = self::impl::Foo;
398+
```
399+
400+
### Negative examples
401+
402+
The following examples should fail to compile under these rules.
403+
404+
#### Non-public items referenced by a pub use
405+
406+
These examples are illegal because they use a `pub use` to re-export
407+
a private item:
372408

373409
````
374410
struct Item { ... }
375411
pub mod module {
376-
use Item;
412+
// Error: Item is not declared as public, but is referenced from
413+
// a `pub use`.
414+
pub use Item;
377415
}
378416
````
379417

380418
````
381-
mod x {
382-
pub struct Item { ... }
383-
}
384-
pub mod module {
385-
use x::Item;
386-
}
419+
struct Foo { ... }
420+
// Error: Non-public item referenced by `pub use`.
421+
pub use Item = Foo;
387422
````
388423

389-
````
390-
pub mod module {
391-
use self::x::Item;
392-
mod x {
393-
pub struct Item { ... }
394-
}
395-
}
396-
````
424+
If it was desired to have a private name that is publicly "renamed" using a pub
425+
use, that can be achieved using a module:
397426

398-
````
399-
struct Item { ... }
400-
pub use Alias = Item;
401-
pub mod x {
402-
pub use Item;
403-
pub mod module {
404-
use Item; // refers to top-level `Item`
405-
}
427+
```
428+
mod impl {
429+
pub struct ItemPriv;
406430
}
407-
````
408-
431+
pub use Item = self::impl::ItemPriv;
432+
```
409433

410434
# Drawbacks
411435

412436
Adds a (temporary) feature gate.
413437

414-
Requires some existing code to opt-in to the feature gate before transitioning
415-
to saner alternatives.
438+
Requires some existing code to opt-in to the feature gate before
439+
transitioning to a more explicit alternative.
416440

417441
Requires effort to implement.
418442

419-
420443
# Alternatives
421444

422445
If we stick with the status quo, we'll have to resolve several bizarre questions
@@ -430,6 +453,13 @@ We could make an exception for private supertraits, as these are not quite as
430453
problematic as the other cases. However, especially given that a more principled
431454
alternative is known (private methods), I would rather not make any exceptions.
432455

456+
The original design defined "public items" using a reachability
457+
predicate. This allowed private items to be exported via `pub use` and
458+
hence considered public. Unfortunately, this design makes it difficult
459+
to determine at a glance whether any particular item was exposed
460+
outside the current module or not, as one must search for a `pub
461+
use`. Moreover, it does not add expressiveness, as demonstrated in the
462+
examples section.
433463

434464
# Unresolved questions
435465

0 commit comments

Comments
 (0)