(Don't have the bandwidth to play with a custom rustc fork atm)
Are you allowing
mod a {
pub impl(crate) trait Spam {
pub(mod) fn spam();
}
}
mod b {
struct S;
impl crate::Spam for S {
fn spam(); // allowed
}
fn test() {
S::spam(); //~ ERROR: not visible
}
}
If so, this is specifically what I'm arguing against. Implementing a trait requires[1] visibility of all non-defaulted trait items.
As such, my argued position is that impl(in $path)
is a suitable and potentially desirable way to opt the default member visibility down from pub(extern)
to pub(in $path)
. And from that rule, an implicit impl(extern)
means the default implicit member visibility is pub(extern)
.
Separating "impl visibility" from "use visibility" for traits makes sense. Separating the two concepts for trait items, especially where the "impl visibility" scope can be larger than the "use visibility" scope, seems highly undesirable.
It's worth reiterating that any restrictions apply solely to the annotated item; e.g. pub(self) mod x
doesn't prevent doing pub use x::PublicItem
.
Under this interpretation, it makes sense that pub(in path) impl(in path) trait
has no impact on the visibility of the trait items; they're all pub(extern)
, and the restriction comes from restrictions on the path-to the item.
The difference is that every item which isn't a trait associated item defaults to pub(mod)
if pub
is not specified. So my concrete proposal is to define the reason for this as being that trait associated items have a default unspecified visibility of the trait they're on's impl
visibility.
You can still change the visibility of a trait associated item by giving it an explicit pub
annotation. It can still be arbitrarily greater or lesser than the trait's impl visibility, but this provides a reason for the difference to the priv
-by-default convention (visibility of the (non-defaulted) members is required in order to implement the trait) and still offers full control.
Interesting aside: would it make sense to allow pub impl(mod) struct S
? The semantics would be disallowing impl S
outside of the module; treating S
as foreign w.r.t. coherence. This would be an interesting way of bringing module and crate barriers closer together in expressive power.
(: I wish we could've sync discussed this at RustConf. Stupid planes.)
Caveat:
default
allows partial trait impls which make things all sort of complicated. ↩︎