@@ -27,7 +27,6 @@ case), and this is the mechanism which should be used for it.
27
27
28
28
[ questions ] : https://github.com/rust-lang/rust/issues/10573
29
29
30
-
31
30
## Examples of strangeness
32
31
33
32
(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
61
60
good idea to do so. If the results are bizarre, then our assumptions should be
62
61
reconsidered. In these cases, it would be wiser to simply say, "don't do that".
63
62
64
-
65
63
## Properties
66
64
67
65
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.
247
245
An item is considered to be publicly exposed by a module if it is declared ` pub `
248
246
by that module, or if it is re-exported using ` pub use ` by that module.
249
247
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
+
250
258
For items which are publicly exposed by a module, the rules are that:
251
259
252
260
* 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:
263
271
* If it is a ` trait ` declaration, items referred to in its super-traits, in the
264
272
trait bounds of its type parameters, and in the signatures of its methods
265
273
(see ` fn ` case above) must be public.
266
-
267
-
274
+
268
275
## What does "public" mean?
269
276
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.
284
278
285
279
### Examples
286
280
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.
289
282
290
- ````
291
- pub mod module {
292
- pub struct Item { ... }
293
- }
294
- ````
283
+ #### Struct fields
295
284
296
285
````
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
300
291
}
301
- ````
302
292
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>,
306
312
}
307
- pub mod module {
308
- use x::Item;
309
- }
310
- ````
311
313
314
+ pub struct Pub { ... }
312
315
````
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) { .. }
318
327
}
319
- ````
328
+ ```
320
329
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) { ... }
325
350
}
326
- ````
327
351
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) { ... }
333
355
}
334
- ````
356
+ ```
335
357
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);
342
367
}
343
- ````
344
368
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.
354
385
}
355
386
}
356
- ````
387
+ ```
357
388
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
362
390
391
+ Note that the path to the public item does not have to be private.
363
392
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 { ... }
370
396
}
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:
372
408
373
409
````
374
410
struct Item { ... }
375
411
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;
377
415
}
378
416
````
379
417
380
418
````
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;
387
422
````
388
423
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:
397
426
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;
406
430
}
407
- ````
408
-
431
+ pub use Item = self::impl::ItemPriv;
432
+ ```
409
433
410
434
# Drawbacks
411
435
412
436
Adds a (temporary) feature gate.
413
437
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 .
416
440
417
441
Requires effort to implement.
418
442
419
-
420
443
# Alternatives
421
444
422
445
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
430
453
problematic as the other cases. However, especially given that a more principled
431
454
alternative is known (private methods), I would rather not make any exceptions.
432
455
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.
433
463
434
464
# Unresolved questions
435
465
0 commit comments