Skip to content
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: Mark reachable but unnameable items as reachable #31641

Merged
merged 3 commits into from Feb 18, 2016

Conversation

Projects
None yet
4 participants
@petrochenkov
Copy link
Contributor

petrochenkov commented Feb 13, 2016

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

@alexcrichton

This comment has been minimized.

Copy link
Member

alexcrichton commented Feb 14, 2016

Thanks @petrochenkov! Knocking out <20k bugs now should get like an extra badge or something...

I'll be honest though in that I'm not really following everything that's going on here, there's quite a few branches which try to add lots of items to the reachable set. I may just not be following what's going on here, but could this perhaps add a few more tests? There's a boatload of test cases dangling off #16734, and I suspect that each addition to the reachable set in this PR corresponds to some test case which wouldn't otherwise be caught.

@petrochenkov

This comment has been minimized.

Copy link
Contributor Author

petrochenkov commented Feb 16, 2016

Updated with more tests.

}
// Corner case: if the variant is reachable, but its
// enum is not, make the enum reachable as well.
self.update(item.id, Some(AccessLevel::Reachable));

This comment has been minimized.

@nikomatsakis

nikomatsakis Feb 16, 2016

Contributor

Does this mean that you should go back and call visit_generics too (i.e., as would have happened on line 323?) If so, maybe we should promote this special case upward somewhere?

This comment has been minimized.

@nikomatsakis

nikomatsakis Feb 16, 2016

Contributor

Also, do we have a regression test for this scenario? (Seems like a good one). If so, you should cite it in the comment here.

This comment has been minimized.

@nikomatsakis

nikomatsakis Feb 16, 2016

Contributor

Ah, I see this scenario is covered in the test you added.

This comment has been minimized.

@petrochenkov

petrochenkov Feb 16, 2016

Author Contributor

Does this mean that you should go back and call visit_generics too (i.e., as would have happened on line 323?)

The whole EmbargoVisitor::visit_crate runs in a loop until it saturates and nothing is updated anymore (yeah, it should probably be optimized into some DFS or BFS, but it's a separate task).
So, the worst thing can happen here is one more loop cycle in exceedingly rare case of unnameable enum with nameable variant.

@nikomatsakis

This comment has been minimized.

Copy link
Contributor

nikomatsakis commented Feb 16, 2016

OK, I think I would r+ modulo my question about the variant case above.

if item_level.is_some() {
self.reach().visit_generics(generics);
for field in struct_def.fields() {
if field.node.kind.visibility() == hir::Public {

This comment has been minimized.

@alexcrichton

alexcrichton Feb 17, 2016

Member

It's been awhile since I've done much with this code, but could you help clarify what's going on here? In other places here it looks like you're checking for "is this reachable" via checking self.get(item.id).is_some(). I think that get returns the level of exported-ness of the id, right?

If that's the case, how come this checks for Public instead of leveraging self.get?

This comment has been minimized.

@petrochenkov

petrochenkov Feb 17, 2016

Author Contributor

Variants and foreign items have their own accessibility levels - they can be reexported independently from their parents enums and foreign modules. So, we have to check them with self.get(id).is_some().
pub struct fields and inherent impl items are always reachable if their parents are reachable, we could check them with self.get(id).is_some() as well, but it wouldn't make any difference.

This comment has been minimized.

@alexcrichton

alexcrichton Feb 17, 2016

Member

Ah ok, thanks for the clarification! For readability could this move to self.get as the same pattern as well?

}

impl<'b, 'a, 'tcx: 'a, 'v> Visitor<'v> for ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
fn visit_ty(&mut self, ty: &hir::Ty) {

This comment has been minimized.

@alexcrichton

alexcrichton Feb 17, 2016

Member

I guess so another thing I'm a little confused about is why two visitors are needed? It looks like the EmbargoVisitor should walk the entire AST, right? In that case, couldn't this just be part of that?

I guess to me this algorithm should look like:

  1. Initialize a reachable set with all public items
  2. While the set has an item in it:
    1. Walk the reachable interface of the item
    2. For each item encountered, add it to the global reachable

This is then repeated iteratively until the set is saturated. There's only one "recurse the interface" step, however, so I'm not entirely sure where this second visitor fits in?

I may and probably am missing something though! Could you help clarify?

This comment has been minimized.

@petrochenkov

petrochenkov Feb 17, 2016

Author Contributor

This PR merely extends the existing pretty inefficient implementation of EmbargoVisito which runs walk_crate several times in a loop without any working set and graph-like traversal. I plan to rewrite it eventually, but don't have time to do it right now.

Regardless of that, having two visitors with different purposes is just convenient. One big visitor walks items and recurses into them, another small and shallow visitor walks item's surfaces without going too deep. Private-in-public visitor has the same separation of concerns.

This comment has been minimized.

@alexcrichton

alexcrichton Feb 17, 2016

Member

Ok, that sounds good to me, thanks for the clarification!

@alexcrichton

This comment has been minimized.

Copy link
Member

alexcrichton commented Feb 17, 2016

Also, thanks for expanding the test! I'm certainly much more comfortable with this now :)

@alexcrichton

This comment has been minimized.

Copy link
Member

alexcrichton commented Feb 17, 2016

ah yeah and to clarify r=me as well, thanks again @petrochenkov!

@petrochenkov petrochenkov force-pushed the petrochenkov:reach branch from eb3bb4e to fadc95e Feb 17, 2016

@petrochenkov

This comment has been minimized.

Copy link
Contributor Author

petrochenkov commented Feb 17, 2016

@alexcrichton
Updated.

@alexcrichton

This comment has been minimized.

Copy link
Member

alexcrichton commented Feb 18, 2016

@bors

This comment has been minimized.

Copy link
Contributor

bors commented Feb 18, 2016

⌛️ Testing commit fadc95e with merge a9430a3...

bors added a commit that referenced this pull request Feb 18, 2016

Auto merge of #31641 - petrochenkov:reach, r=alexcrichton
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

@bors bors merged commit fadc95e into rust-lang:master Feb 18, 2016

2 checks passed

continuous-integration/travis-ci/pr The Travis CI build passed
Details
homu Test successful
Details

@petrochenkov petrochenkov deleted the petrochenkov:reach branch Sep 21, 2016

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.