-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
privacy: Rewrite VisiblePrivateTypesVisitor #29973
Conversation
Edit: Fixed in 7b0f1d6 |
There are two ways to reduce the breakage:
will be permitted. I like this variant, it makes
Edit: as a minimum, type aliases should be substituted when determining publicity of |
☔ The latest upstream changes (presumably #29530) made this pull request unmergeable. Please resolve the merge conflicts. |
cf28bce
to
7b0f1d6
Compare
Rebased. |
Exciting! I was on PTO since Thu, I'll try to read this today or tomorrow. |
(I am scheduling a crater run now.) |
Preliminary crater report: https://gist.github.com/nikomatsakis/e7feaa7c4bc0ebcc6559 I've not dug into this at all. |
Note that the root regression division may mean that this change is underestimating the amount of breakage. |
TL;DR: People don't write quickcheck-0.2.24 - Private trait in where clause (out of date) Top non-root regressions are due to aho-corasick-0.3.4 (it has private type alias in trait methods, solvable by simple normalization) or due to xml-rs-0.2.2 1 By "simple normalization" I mean substitution of type alias
before checking. |
Proposed way forward:
|
Another more extreme variants:
|
I was going to propose mostly the same thing. But some quibbles:
It would be better to emit a lint, I think. I've been wanting to propose that we add a "future-compatibility" lint for this purpose. The reasons to prefer a lint are:
However, I wanted to try and advertise the idea of this lint a bit more broadly for some reason, but maybe we can just add it here and then tweak the design. (We have a bit of time before this change hits stable.)
Sorry, what is "simple type alias normalization"? |
Footnote 1 in the previous message #29973 (comment)
Yeah, I should have added an unresolved question "what kind of warning exactly?" to my proposed way forward. |
I'm not sure, but I think you can view this as a feature or a bug. That is, we have had regressions in rustc where RFC1214 warnings were not noticed because they occurred in stage1 and were not subject to deny(warnings). I tend to think you should give people what they ask for. As you say, it won't break dependencies, and you can always re-enable warnings. It also lets us get a more accurate crater measurement, since the issue of "root regressions" is moot. |
...ok, that makes sense. But what is "full normalization" then? In some sense, the type checker already does this sort of normalization (for better and worse). That is, it expands type aliases in its internal representation and keeps no record of them. But I don't think this is particularly useful for your check because, when it comes to privacy, you care about the path that people used to reach something, and not just the item they reached in the end (the type checker doesn't track the path). Anyway, privacy is (usually) not something the type checker should have to be overly concerned with I think. |
Substitution of type aliases beyond the simplest case - associated type aliases (when possible), type aliases with default type parameters.
I don't suggest to do it in type checker, but I presume that type checker has tools for doing it, which can be reused in rustc_privacy somehow. Anyway, the simplest substitution can be done trivially in privacy without involving anything from type checker. Without this "normalization" some regressions from the crater report look pretty silly, e.g. from
In place of the library authors I'd start to resent - "Hey, It's |
Ah. I'm not sure this kind of normalization makes sense or is necessary. After all, there is no "path" to follow when you do associated type normalization, for example, and there are already privacy rules that guarantee that the types that result from associated type normalization will be publicly accessible. (Basically, things appearing in impls, must be declared
Yes, I certainly see your point, and I've been annoyed by this same thing in the past. Basically wanting some private aliases and shorthands that you don't necessarily want to expose. It's tricky though because sometimes the type aliases are important things that rustdoc probably wants to preserve (e.g., cc @rust-lang/lang thoughts on this? (Normalization of type aliases) |
That was my idea as well. After #29822 rustdoc has all the necessary information to discern between these two kinds of type aliases. |
7b0f1d6
to
88c3441
Compare
Updated with the old visitor restored, warnings used instead of some errors, and lint used instead of a plain warning. |
Updated with (non-associated) type alias substitution. |
I'll schedule another crater run. |
This time around crater reports one failure. |
This failure is expected, it's a result of the fix for resolve, I'm not sure it deserves a warning period, but if we want to be extra careful maybe it makes sense to put a warning there as well. |
Cool, good to know! I'll leave the review to @nikomatsakis, but I'm pretty excited to see the nuts and bolts tightened up here! |
OK, I did a first pass and by and large I think this is pretty nice. It's hard for me to be sure if there are corner cases not covered but it certainly seems like a big improvement. I'm not quite ready to r+ yet though, largely because there are a few policy issues I'd like to resolve:
One other point: I'd like to ensure that there is a comprehensive and systematic set of tests for all the edge cases we can come up with. This is hard for me to tell, since there are older tests and of course the newer tests you've added, and the tests don't seem to share any distinct naming scheme. One nit I have with your naming is that you added most of the new tests as Some things I came up with that I'd like to know whether there are tests for:
Anyway, I have encountered this same problem (how to manage and track what tests exist and which tests we may want to exist) in other contexts and still find it frustrating! I'd like some kind of side files in the test directory that show these matrices and which tests cover what. Obviously out of scope for this PR. |
I agree with this now. |
I'd like to leave the constant checking to a separate PR, because it needs discussion. It's also a new kind of restriction that can be unexpected for users. I'll create an issue for this. |
Heh, a good question. If we REALLY want to guarantee that one can freely change a constant, we are indeed forced to a pretty extreme position -- too extreme, in my view. For example,
Given the improvements to const fn evaluation that @eddyb and I have been talking about, it is certainly plausible that we could actually implement the above fn at some point in the not-that-distinct future. In that case, we could regard this as illegal, because it "exposes" Of course you don't need to go to such esoteric examples. It's enough to have something like:
I may want to keep the precise A compromise might be to say that we do not check for privacy in the RHS of a constant definition nor in a
but if you are going to do that, you have to at least do it explicitly. Put another way, we guarantee for you (I think?) that the only constants the caller can observe are those that are declared public, but we leave it to you to vet that this only exposes what you intended. I am not sure if I find that persuasive. It doesn't feel very consistent with the rest of the "private things appearing in public APIs" logic. Another compromise might be to say that we do not check the body of @rust-lang/lang, thoughts on these thorny questions about public constants? @petrochenkov, do you think any similar concerns arise for type aliases? I don't think so, particularly given your "normalization" rule, which effectively means that the body of the type alias would have to be "deeply" public anyhow (iow, type alias normalization is kind of implementing the stricter rule). We've certainly got to land some of this excellent code soon! |
I agree with this inclination. The only question in my mind is what to do about type alias normalization. Certainly if we revert it, we can always add it back in later (perhaps with an RFC). This sort of makes sense, since it is weakening existing, stable rules. |
One more comment about type alias normalization - it still has to be performed for impls:
so most of the code for it will stay in place. |
Ah, true. |
Type aliases are still substituted when determining impl publicity
Updated with type aliases not substituted. |
@bors r+ p=2 |
📌 Commit 785cbe0 has been approved by |
Some notes: This patch enforces the rules from [RFC 136](https://github.com/rust-lang/rfcs/blob/master/text/0136-no-privates-in-public.md) and makes "private in public" a module-level concept and not crate-level. Only `pub` annotations are used by the new algorithm, crate-level exported node set produced by `EmbargoVisitor` is not used. The error messages are tweaked accordingly and don't use the word "exported" to avoid confusing people (#29668). The old algorithm tried to be extra smart with impls, but it mostly led to unpredictable behavior and bugs like #28325. The new algorithm tries to be as simple as possible - an impl is considered public iff its type is public and its trait is public (if presents). A type or trait is considered public if all its components are public, [complications](https://internals.rust-lang.org/t/limits-of-type-inference-smartness/2919) with private types leaking to other crates/modules through trait impls and type inference are deliberately ignored so far. The new algorithm is not recursive and uses the nice new facility `Crate::visit_all_items`! Obsolete pre-1.0 feature `visible_private_types` is removed. This is a [breaking-change]. The two main vectors of breakage are type aliases (#28450) and impls (#28325). I need some statistics from a crater run (cc @alexcrichton) to decide on the breakage mitigation strategy. UPDATE: All the new errors are reported as warnings controlled by a lint `private_in_public` and lint group `future_incompatible`, but the intent is to make them hard errors eventually. Closes #28325 Closes #28450 Closes #29524 Closes #29627 Closes #29668 Closes #30055 r? @nikomatsakis
@petrochenkov are you aware of an open issue concerning the interactions between inference and privacy? |
I opened one yesterday - #30476 |
I'm investigating some breakage in Diesel, and I believe this PR is the source. Just to make sure I'm clear, the intention was to disallow using private type aliases that appear anywhere? I've been using them quite a bit to shorten some more gnarly where clauses. I can make the type aliases public and |
@sgrif
? If yes, then my intention was to allow this, that's why type aliases were originally substituted, but it was reverted later to follow the letter of the RFC. It can be fixed at any moment (by removing three lines of code), but it needs a decision from the lang team. |
cc #16463 |
Fixes #16734 and probably some other issues This is a continuation of #29822, but the algorithm is mostly a copy of #29973, so r? @alexcrichton or @nikomatsakis
Some notes:
This patch enforces the rules from RFC 136 and makes "private in public" a module-level concept and not crate-level. Only
pub
annotations are used by the new algorithm, crate-level exported node set produced byEmbargoVisitor
is not used. The error messages are tweaked accordingly and don't use the word "exported" to avoid confusing people (#29668).The old algorithm tried to be extra smart with impls, but it mostly led to unpredictable behavior and bugs like #28325.
The new algorithm tries to be as simple as possible - an impl is considered public iff its type is public and its trait is public (if presents).
A type or trait is considered public if all its components are public, complications with private types leaking to other crates/modules through trait impls and type inference are deliberately ignored so far.
The new algorithm is not recursive and uses the nice new facility
Crate::visit_all_items
!Obsolete pre-1.0 feature
visible_private_types
is removed.This is a [breaking-change].
The two main vectors of breakage are type aliases (#28450) and impls (#28325).
I need some statistics from a crater run (cc @alexcrichton) to decide on the breakage mitigation strategy.
UPDATE: All the new errors are reported as warnings controlled by a lint
private_in_public
and lint groupfuture_incompatible
, but the intent is to make them hard errors eventually.Closes #28325
Closes #28450
Closes #29524
Closes #29627
Closes #29668
Closes #30055
r? @nikomatsakis