Skip to content

SE-0169: Add support for shared private #9098

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

Merged
merged 4 commits into from
May 2, 2017

Conversation

KingOfBrian
Copy link
Contributor

This PR implements SE-0169 and allows the private scope to be shared between types and extensions inside of a file. This follows the approach Jordan spelled out in SR-4616.

The one slight deviation is that I didn't change the way the private AccessScope is constructed, but changed the isChildOf check to also use the private scope check. Doing both didn't seem to make sense and I believe isChildOf needs to use the private scope check.

For testing I added a test Sema/accessibility_shared_private.swift with explicit checks for multi-file shared private behavior. I also copied the existing Sema/accessibility_private.swift to the Compatibility directory, and updated the test for Swift 4 behavior. I think the test coverage is pretty good, but any ideas for additional testing would be great.

Resolves SR-4616.

lastExtension = ED;

// If there's no last extension, return the supplied context.
return lastExtension ?: DC;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We try not to use GNU extensions like ?:, please just write lastExtension ? DC : nullptr

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you mean lastExtension ? lastExtension : DC.

@slavapestov
Copy link
Contributor

I have a cosmetic nitpick -- the name 'shared private' is not great. How about we talk about 'private', 'fileprivate', and 'swift 3 private'.

@xwu
Copy link
Collaborator

xwu commented Apr 28, 2017

At this rate, might as well future-proof and call these things "Swift 4 private", "Swift 2 private", and "Swift 3 private" :P

Copy link
Contributor

@jrose-apple jrose-apple left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for working on this, Brian! (And Xiaodi.)

Hm. I'm not comfortable with this solution as is because it only changes isChildOf, and not == or intersectWith. Won't that lead to troubles down the line?

// sourceDC does not represent a type.
auto sourceNTD = sourceDC->getAsNominalTypeOrNominalTypeExtensionContext();
auto useSF = useDC->getParentSourceFile();
if (useSF != sourceDC->getParentSourceFile() || !sourceNTD)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: Please don't try to combine these checks because it means wasting effort (either looking up the base nominal, or looking for the useDC's parent file).

@KingOfBrian
Copy link
Contributor Author

intersectsWith uses isChildOf so I think that will work correctly. I totally missed the equal operator. I'll add back your original suggestion of using the private context in the constructor, I think that will fix ==.

@slavapestov
Copy link
Contributor

@KingOfBrian You might want to try enabling this unconditionally, and building the standard library and overlays, just to get a bit of additional testing -- if you hit a crash, add some new tests.

@KingOfBrian
Copy link
Contributor Author

Good thought -- I rebuilt everything with the swift 3 guard commented out and no crashes.

How would I just rebuild the stdlib and overlays btw?

@CodaFi
Copy link
Contributor

CodaFi commented Apr 29, 2017

How would I just rebuild the stdlib and overlays btw?

If you build with ninja, you can cd into the Swift build directory and just call

$ ninja swift-stdlib 

I'm not sure the overlays have a target, but you can try to find it by grepping the output of

$ ninja -t targets all

@DougGregor
Copy link
Member

@swift-ci please smoke test

Copy link
Contributor

@jrose-apple jrose-apple left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm definitely happier with this. Nice work, Brian! I still have several small comments here but they're all things that could be addressed post-commit.

@@ -48,7 +53,7 @@ class AccessScope {
/// \see DeclContext::isChildContextOf
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: This doc comment \see should probably be dropped or changed to \sa.

@@ -48,7 +53,7 @@ class AccessScope {
/// \see DeclContext::isChildContextOf
bool isChildOf(AccessScope AS) const {
if (!isPublic() && !AS.isPublic())
return getDeclContext()->isChildContextOf(AS.getDeclContext());
return allowsPrivateAccess(getDeclContext(), AS.getDeclContext());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: This case also handles internal, so maybe just make this allowsAccess? Or make it a method like isChildSlowPath, which would help preserve the distinction at the call site between the useDC and the sourceDC.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Ah, I see now that NameLookup.cpp tries to access this logic directly. It might just make sense to change that checkAccessibility over to using access scopes explicitly instead of trying to be clever and do everything with DeclContexts.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll update it to allowsAccess at the very least and will try to update checkAccessibility. I didn't like how there were multiple methods of doing this, but I was trying not to disturb too much. Let me see how it goes!

_ = PrivateInner() // expected-error {{'PrivateInner' is inaccessible due to 'private' protection level}}
_ = Container.PrivateInner() // expected-error {{'PrivateInner' is inaccessible due to 'private' protection level}}
_ = PrivateInner()
_ = Container.PrivateInner()
}

// FIXME: Why do these errors happen twice?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like the FIXME no longer applies.

@@ -0,0 +1,76 @@
// RUN: rm -rf %t && mkdir -p %t
// RUN: %utils/split_file.py -o %t %s
// RUN: %target-swift-frontend -swift-version 4 -typecheck %t/declarations.swift %t/other_file_extensions.swift -verify
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you also run this test in multi-file mode, using -primary-file before each file in turn? Sometimes that behaves differently from whole-module mode (which is the default when invoking %target-swift-frontend directly).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm struggling to find a clean way to do this. it looks like there's a @-1 style syntax, that changes which run of FileCheck it matches, but I can't get it to work right or find any documentation on it. Any documentation other than the lit source?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like that @-1 syntax just changes the line, so I'm out of ideas how to make this test valid without 3 copies of this test =/

Copy link
Contributor Author

@KingOfBrian KingOfBrian May 4, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like VerifyDiagnosticConsumer defines the expected-[] behavior. It would be great if that syntax supported the idea of a prefix like FileCheck, then this would be pretty trivial. Any other ideas on how to update this test @jrose-apple ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(FileCheck docs)

I think using FileCheck instead of / in addition to -verify is probably the best way to go.I wouldn't worry about the notes, just the main errors.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good, thanks!

sourceDC = getPrivateDeclContext(sourceDC, useSF);
while (!useDC->isModuleContext()) {
useDC = getPrivateDeclContext(useDC, useSF);
if (useDC == sourceDC)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically an access scope is not a child access scope if it's the same access scope.

@ematejska ematejska merged commit 75a1dca into swiftlang:master May 2, 2017
ematejska pushed a commit that referenced this pull request May 3, 2017
SE-0169: Add support for shared private(cherry picked from commit 75a1dca)
ematejska pushed a commit that referenced this pull request May 3, 2017
Merge pull request #9098 from KingOfBrian/feature/SE-0169
@ematejska
Copy link
Contributor

@KingOfBrian Please open a pull request with the Changelog updated as well if you haven't already.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants