-
Notifications
You must be signed in to change notification settings - Fork 10.5k
@_implementationOnly: fix over-eager checking for vars in extensions #24629
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
Conversation
@swift-ci Please test |
lib/Sema/TypeCheckAccess.cpp
Outdated
@@ -1660,21 +1665,27 @@ class ExportabilityChecker : public DeclVisitor<ExportabilityChecker> { | |||
return true; | |||
} | |||
|
|||
void checkExtensionMemberIfNeeded(const ValueDecl *D) { | |||
auto *extension = dyn_cast<ExtensionDecl>(D->getDeclContext()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's kind of odd that this is called for every member but it only checks and diagnoses the extension itself?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe the name is wrong? The trouble is we only want to diagnose the extension if one of the members is public.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Actually, strictly speaking I'd like this to be a diagnostic on the member somehow even though the problem is at the extension level, but that can come when we productize this thing.)
New implementation per Slava's suggestion. @swift-ci Please test |
lib/Sema/TypeCheckAccess.cpp
Outdated
checkType(ED->getExtendedTypeLoc(), ED, | ||
getDiagnoseCallback(ED), getDiagnoseCallback(ED)); | ||
// FIXME: include a note as to why this restriction is being enforced, | ||
// i.e. there are public members. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you planning to leave this as a FIXME until this turns into a public-facing feature?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah. :-/ It's what was there before this PR, and while it's not even that hard it's also not necessarily worth my time at the moment.
@@ -87,18 +87,26 @@ public var testMultipleBindings1: Int? = nil, testMultipleBindings2: BadStruct? | |||
public var testMultipleBindings3: BadStruct? = nil, testMultipleBindings4: Int? = nil // expected-error {{cannot use struct 'BadStruct' here; 'BADLibrary' has been imported as implementation-only}} | |||
|
|||
extension BadStruct { // expected-error {{cannot use struct 'BadStruct' here; 'BADLibrary' has been imported as implementation-only}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can the message at least say something like "Cannot use struct 'BadStruct' in extension with public members"? Or use a note or something, I don't care—just let the user know somehow that the problem is that the extension has public members, because if you don't say so, they'll have no idea what's wrong.
The logic I had here checked whether an extension used an implementation-only type whenever there was a declaration within that extension that needed checking...but unfortunately that included not just PatternBindingDecls (whose access is filtered at a later step) but things like IfConfigDecls (#if). Change this to only check signatures of extensions with ABI-public members, something that is tested once when visiting an ExtensionDecl. Additionally, skip AccessorDecls entirely, since they'll be tested as part of the corresponding subscript or var. This saves a duplicate diagnostic. rdar://problem/50541589
Diagnostics clarified per Brent's comment. @swift-ci Please test |
Build failed |
Build failed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are bits I don't love, but I don't think you have to change them.
@@ -86,27 +86,35 @@ public var (testBadTypeTuplePartlyInferred3, testBadTypeTuplePartlyInferred4): ( | |||
public var testMultipleBindings1: Int? = nil, testMultipleBindings2: BadStruct? = nil // expected-error {{cannot use struct 'BadStruct' here; 'BADLibrary' has been imported as implementation-only}} | |||
public var testMultipleBindings3: BadStruct? = nil, testMultipleBindings4: Int? = nil // expected-error {{cannot use struct 'BadStruct' here; 'BADLibrary' has been imported as implementation-only}} | |||
|
|||
extension BadStruct { // expected-error {{cannot use struct 'BadStruct' here; 'BADLibrary' has been imported as implementation-only}} | |||
public func testExtensionOfBadType() {} // FIXME: Should complain here instead of at the extension decl. | |||
extension BadStruct { // expected-error {{cannot use struct 'BadStruct' in an extension with public or '@usableFromInline' members; 'BADLibrary' has been imported as implementation-only}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Excellent.
} | ||
|
||
extension Int: BadProto {} // expected-error {{cannot use protocol 'BadProto' here; 'BADLibrary' has been imported as implementation-only}} | ||
struct TestExtensionConformanceOkay {} | ||
extension TestExtensionConformanceOkay: BadProto {} // okay | ||
|
||
public protocol TestConstrainedExtensionProto {} | ||
extension Array: TestConstrainedExtensionProto where Element == BadStruct { // expected-error {{cannot use struct 'BadStruct' here; 'BADLibrary' has been imported as implementation-only}} | ||
extension Array: TestConstrainedExtensionProto where Element == BadStruct { // expected-error {{cannot use struct 'BadStruct' in an extension with conditional conformances; 'BADLibrary' has been imported as implementation-only}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would this be allowed if TestConstrainedExtensionProto
was internal
or less? If so, I wish the message conveyed that...but as I started writing an example, I realized that fully describing it gets pretty long and complicated. I guess this Is fine for now; we can introduce notes pointing to the relevant declarations when we package this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we don't actually allow that right now even though we probably should.
@@ -249,7 +249,7 @@ diagnoseGenericArgumentsExportability(SourceLoc loc, | |||
ASTContext &ctx = M->getASTContext(); | |||
ctx.Diags.diagnose(loc, diag::conformance_from_implementation_only_module, | |||
rootConf->getType(), | |||
rootConf->getProtocol()->getFullName(), M->getName()); | |||
rootConf->getProtocol()->getFullName(), 0, M->getName()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It'd be better to expose the Reason
enum widely enough to use it here, but I can live with this if you can.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I'm not sure where it would live. Splitting it into two diagnostics might make more sense, but I think this is okay specifically because it's 0 and the first case and not any of the others.
@@ -3678,7 +3678,7 @@ void ConformanceChecker::ensureRequirementsAreSatisfied( | |||
conformanceBeingChecked->getLoc(), | |||
diag::conformance_from_implementation_only_module, | |||
rootConformance->getType(), | |||
rootConformance->getProtocol()->getName(), M->getName()); | |||
rootConformance->getProtocol()->getName(), 0, M->getName()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As above.
…wiftlang#24629) The logic I had here checked whether an extension used an implementation-only type whenever there was a declaration within that extension that needed checking...but unfortunately that included not just PatternBindingDecls (whose access is filtered at a later step) but things like IfConfigDecls (#if). Change this to only check signatures of extensions with ABI-public members, something that is tested once when visiting an ExtensionDecl. Additionally, skip AccessorDecls entirely, since they'll be tested as part of the corresponding subscript or var. This saves a duplicate diagnostic. rdar://problem/50541589 (cherry picked from commit 3b4bb19)
…24629) (#24843) The logic I had here checked whether an extension used an implementation-only type whenever there was a declaration within that extension that needed checking...but unfortunately that included not just PatternBindingDecls (whose access is filtered at a later step) but things like IfConfigDecls (#if). Change this to only check signatures of extensions with ABI-public members, something that is tested once when visiting an ExtensionDecl. Additionally, skip AccessorDecls entirely, since they'll be tested as part of the corresponding subscript or var. This saves a duplicate diagnostic. rdar://problem/50541589 (cherry picked from commit 3b4bb19)
The logic I had here checked whether an extension used an implementation-only type whenever there was a declaration within that extension that needed checking...but unfortunately that included not just PatternBindingDecls (whose access is filtered at a later step) but things like IfConfigDecls (
#if
). Change this to only check extension signatures for ValueDecl members of extensions, where we can properly check access beforehand. Additionally, don't bother doing this checking for accessors, since we'll have already done it for the corresponding VarDecl or SubscriptDecl.rdar://problem/50541589