-
-
Notifications
You must be signed in to change notification settings - Fork 14.4k
resolve: Report more visibility-related early resolution ambiguities for imports #149596
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
@bors try |
This comment has been minimized.
This comment has been minimized.
resolve: Report more early resolution ambiguities for imports
|
|
|
@craterbot run mode=check-only p=1 crates=https://crater-reports.s3.amazonaws.com/pr-149145/retry-regressed-list.txt |
|
👌 Experiment ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more |
|
🚧 Experiment ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more |
|
🎉 Experiment
Footnotes
|
9c25090 to
1ea10c2
Compare
This comment has been minimized.
This comment has been minimized.
|
@bors try |
This comment has been minimized.
This comment has been minimized.
resolve: Report more early resolution ambiguities for imports
|
@rfcbot fcp merge lang |
|
Team member @tmandry has proposed to merge this. The next step is review by the rest of the tagged team members: No concerns currently listed. Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! cc @rust-lang/lang-advisors: FCP proposed for lang, please feel free to register concerns. |
|
Possibly-relevant rules, by the way, in the pending Reference PR, include:
(See the PR for examples for each of these rules and explanatory admonitions.) |
|
Let's talk through what we're doing here. Today, this is an error: mod m {
pub struct S {}
}
macro_rules! mac { () => { struct S {} }}
pub use m::*;
mac!();
pub use S as _;
//~^ error[E0659]: `S` is ambiguousWhy? What do the rules say? First:
Are there two name candidates? Yes; the struct in Do they resolve to the same entity? No; they have two distinct definitions. Is one permitted to shadow the other? Let's see.
This is indeed
So this would be allowed normally. If
Because the Conversely, this is accepted today: mod m {
pub struct S {}
}
macro_rules! mac { () => { use m::S; }}
pub use m::*;
mac!();
pub use S as _; //~ OKWhy? Are there two name candidates? Yes. But now they resolve to the same entity. The ambiguity still exists, but because both resolution paths lead to the same definition, the compiler currently considers it benign and accepts it. Should we lint about this? @petrochenkov gives three rules:
Taking them in turn: One. What's ambiguous mean? As I read this (and, @petrochenkov or @yaahc, correct me if I'm wrong), this is suggesting that two declarations are ambiguous when they are candidates for the same name in the same scope and neither is permitted to shadow the other or the resolution order would make the shadowing unpredictable. I.e., they are ambiguous when we would give an error if the definitions of those declarations are not the same. So these declarations are ambiguous. Two. They have the same definition. Do they have different visibilities? Yes. Three. The visibility of the import is QED. We lint this case. Net-net, with this FCW, we're reducing the scope of what we consider to be a benign ambiguity. Based on that understanding... @rfcbot reviewed |
I do note a possible counterexample to the way I stated it here (in the i.e.). We give an error for this: mod m1 {
pub struct S {}
}
mod m2 {
pub struct S {}
}
pub mod m3 {
pub use crate::m1::*;
use crate::m2::*;
}
pub use m3::S as _;
//~^ error[E0659]: `S` is ambiguousBut the PR branch does not warn if we make the definition for each declaration the same: mod m1 {
pub struct S {}
}
pub mod m3 {
pub use crate::m1::*;
use crate::m1::*;
}
pub use m3::S as _;Do we not consider these declarations ambiguous, or what's the rule we're using to decide to not lint here? |
They are also ambiguous, this part of the lint is just not implemented yet. I plan to implement it too, but to do that you'd need something like https://github.com/petrochenkov/rust/tree/neverwrite, which it is mostly blocked on #149195. |
|
Makes sense. So we're expecting a later expansion of this lint. |
|
@petrochenkov, I wanted to ask you a question. Thinking through this issue made me realize that my "mental model" for how How I think the code worksI believe that when you have a mod mod_a {
use crate::mod_b::B;
pub struct A;
}
mod mod_b {
pub struct B;
}
use mod_a::A; // errors, the `use` is not public hereHowever it also means that this example errors: mod mod_a {
use crate::mod_b::B as B2; // "private" item
pub use B2 as B3; // re-exporting a private item as public, error
pub struct A;
}
mod mod_b {
pub struct B;
}
use mod_a::B2; // errors, the `use` is not public here
use mod_a::B3; // errors, the `use` is not public hereIndeed, I think this is the case that the issue describes. An alternative modelThings could also work a bit different. Instead of having To resolve a path In a This implies that the first example errors, but the second example behaves a touch differently: mod mod_a {
use crate::mod_b::B as B2; // "private" item
pub use B2 as B3; // re-exporting a private item as public, error
pub struct A;
}
mod mod_b {
pub struct B;
}
use mod_a::B2; // errors, the `use` is not public here
use mod_a::B3; // OK!
My question then
|
Yes, but there are more nuances because mod m {
pub type name = ();
pub(crate) fn name() {}
macro name() {}
}
pub use m::name;
// Works like
pub use m::name as type;
pub(crate) use m::name as fn;
// macro `name` is filtered away as too private, not imported, exactly like with glob imports pub use m::*;
// Works like
pub use m::name as type;
pub(crate) use m::name as fn;
// macro `name` is filtered away as too private, not imported |
This comment was marked as resolved.
This comment was marked as resolved.
The new ambiguities are reported when the import's visibility is ambiguous and may depend on the resolution/expansion order.
a9a2fe7 to
8238790
Compare
|
This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed. Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers. |
|
☔ The latest upstream changes (presumably #139493) made this pull request unmergeable. Please resolve the merge conflicts. |
|
r? @yaahc |
|
ping @joshtriplett @nikomatsakis @scottmcm |
|
Checking a box on this. Separately, I'm looking forward to the future edition changes proposed in #148610 to simplify |
|
🔔 This is now entering its final comment period, as per the review above. 🔔 |
|
@rfcbot reviewed I was reluctant to check my box here but I've become convinced that the current behavior is nice in its own way and that changing it in the way I proposed might cause private APIs to become "accidentally" exposed. The example that @tmandry showed me, which I believe came from @Nadrieril, is: mod internal {
mod inner {
pub struct Foo;
}
pub(crate) use inner::Foo;
pub struct Bar;
}
pub use internal::*; // `Foo` would now be part of the public API of the crateHere, here the intent of the Put another way: what I consider most important is "locality of reasoning" about visibility. I want to be able to look at a particular declaration and understand who might be relying on it. And I can see that the model I proposed in fact violates that locality of reasoning in an example like this. Not for the So, I'm convinced. Thanks all for the discussion. I think it'd be useful to try and capture these notes somewhere for the next time I am confused. |
The new ambiguities are reported when the import's visibility is ambiguous and may depend on the resolution/expansion order.
Detailed description: #149596 (comment).