The following compiles today, and the struct X contains an instance of Foo from the module declared here. With your proposal it would now refer to an instance of Foo from a (potentially non-existing) feature crate. This is a breaking change.
mod api {
pub mod feature {
pub struct Foo;
}
}
struct X(api ::feature::Foo);
I don't think I understood the question. Are you saying that api::x should continue to have the current meaning since you can use pub ::x to get almost the other meaning? This seem pretty special cased to me.
The leading :: has a meaning: it forces the next identifier to refer to a crate rather than any module. The following example doesn't work if you remove the leading ::
mod x {
pub mod std {
pub mod string {
pub struct String;
}
}
pub struct X(pub ::std::string::String);
}
fn f() {
let o = x::X("abc".to_owned());
o.0;
}
With api it’s a bit more mild, crate ::foo is strongly ambiguous, in that there’s no way to disambiguate that. With api, the disambiguating can be api ::r#api / r#api::r#api. So, in theory these two approaches would work, with varying degrees of churn:
make api a strong keyword in an edition X, requiring use of r#api if compat warnings are on in the previous edition.
make api a contextual keyword, which would only require r#api in genuinely ambiguous cases (namely, in tupple struct fields). That is, if api can be parsed as a keyword, it is parsed as a keyword, and r# is mandatory for alternative reading.
We have several cases in the language requiring local disambiguation between possible parses, and this one is no different.
I've been consistently pointing this out in every thread discussing crate visibility, but in the end this nonsense was even declared the official reason to remove the feature
I stand corrected, thanks! There are indeed trivial disambiguators for crate ::foo: pub(crate) ::foo
or pub(self) crate::foo
(depending on which parse we pick by default), if I spend 30 seconds actually thinking about this