

Relax priv-in-pub lint on generic bounds and where clauses of trait impls. by js...
source link: https://github.com/rust-lang/rust/pull/90586
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

The priv-in-pub lint is a legacy mechanism of the compiler, supplanted by a reachability-based type privacy analysis. This PR does not relax type privacy; it only relaxes the lint (as proposed by the type privacy RFC) in the case of trait impls.
Current Behavior
On public trait impls, it's currently an error to have a where
bound constraining a private type with a trait:
pub trait Trait {} pub struct Type {} struct Priv {} impl Trait for Priv {} impl Trait for Type where Priv: Trait // ERROR {}
...and it's a warning to have have a public type constrained by a private trait:
pub trait Trait {} pub struct Type {} pub struct Pub {} trait Priv {} impl Priv for Pub {} impl Trait for Type where Pub: Priv // WARNING {}
This lint applies to where
clauses in other contexts, too; e.g. on free functions:
struct Priv<T>(T); pub trait Pub {} impl<T: Pub> Pub for Priv<T> {} pub fn function<T>() where Priv<T>: Pub // WARNING {}
These constraints could be relaxed without issue.
New Behavior
This lint is relaxed for where
clauses on trait impls, such that it's okay to have a where
bound constraining a private type with a trait:
pub trait Trait {} pub struct Type {} struct Priv {} impl Trait for Priv {} impl Trait for Type where Priv: Trait // OK {}
...and it's okay to have a public type constrained by a private trait:
pub trait Trait {} pub struct Type {} pub struct Pub {} trait Priv {} impl Priv for Pub {} impl Trait for Type where Pub: Priv // OK {}
Rationale
While the priv-in-pub lint is not essential for soundness, it can help programmers avoid pitfalls that would make their libraries difficult to use by others. For instance, such a lint is useful for free functions; e.g. if a downstream crate tries to call the function
in the previous snippet in a generic context:
fn callsite<T>() where Priv<T>: Pub // ERROR: omitting this bound is a compile error, but including it is too { function::<T>() }
...it cannot do so without repeating function
's where
bound, which we cannot do because Priv
is out-of-scope. A lint for this case is arguably helpful.
However, this same reasoning doesn't hold for trait impls. To call an unconstrained method on a public trait impl with private bounds, you don't need to forward those private bounds, you can forward the public trait:
mod upstream { pub trait Trait { fn method(&self) {} } pub struct Type<T>(T); pub struct Pub<T>(T); trait Priv {} impl<T: Priv> Priv for Pub<T> {} impl<T> Trait for Type<T> where Pub<T>: Priv // WARNING {} } mod downstream { use super::upstream::*; fn function<T>(value: Type<T>) where Type<T>: Trait // <- no private deets! { value.method(); } }
This PR only eliminates the lint on trait impls. It leaves it intact for all other contexts, including trait definitions, inherent impls, and function definitions. It doesn't need to exist in those cases either, but I figured I'd first target a case where it's mostly pointless.
Other Notes
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK