-
Notifications
You must be signed in to change notification settings - Fork 10.4k
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
[SE implementation] Ownership keyword removal in protocols #11744
[SE implementation] Ownership keyword removal in protocols #11744
Conversation
Neat @swift-ci please smoke test |
@jrose-apple Do you know of a similar warning for this in Clang for Objective-C protocols? I know of authors that assume a |
@@ -3102,6 +3102,11 @@ ERROR(invalid_weak_ownership_not_optional,none, | |||
"'weak' variable should have optional type %0", (Type)) | |||
ERROR(invalid_weak_let,none, | |||
"'weak' must be a mutable variable, because it may change at runtime", ()) | |||
ERROR(protocol_property_declarations_cannot_specify_ownership,none, | |||
"ownership cannot be specified in protocols", ()) |
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 would prefer if the diagnostic mentioned the keyword in question, like "'weak' properties are not supported in protocols"
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 Greg's wording is better, actually. This way people won't be concerned about using a weak property to satisfy a requirement.
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.
(which, admittedly, might be dangerous, but let's say unowned
instead)
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 the following be clearer error messages?
ownership keyword 'weak' is not supported in protocols
ownership keyword 'unowned' is not supported in protocols
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.
@gspiers My meta-suggestion is to look for existing diagnostics concerning ownership keywords, and try to make the new ones consistent with the existing ones.
lib/Sema/TypeCheckAttr.cpp
Outdated
@@ -2063,6 +2063,20 @@ void TypeChecker::checkOwnershipAttr(VarDecl *var, OwnershipAttr *attr) { | |||
|
|||
diagnose(var->getStartLoc(), D, (unsigned) ownershipKind, underlyingType); | |||
attr->setInvalid(); | |||
return; | |||
} else if (var->getDeclContext()->getAsProtocolOrProtocolExtensionContext()) { |
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.
This will also be true for protocol extensions. I don't think there should be any prohibition against defining weak or unowned properties in protocol extensions, and I don't see anything similar in the proposal. Please add a test that this case continues to work.
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.
We don't actually let you put stored properties in a protocol extension today (instance or type properties), so it won't make much of a difference, but Slava's right that it shouldn't get this diagnostic.
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.
Do we not allowed computed weak/unowned properties? I guess that doesn't make much sense, but I wasn't aware of the restriction.
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.
Huh, it looks like we do. In that case, I'm not sure whether this is a good idea or not, but that's an issue for the review, not for the implementation.
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.
Perhaps we should broaden the SE proposal to ban computed properties with ownership qualifiers also. It doesn't really make any sense to declare a weak or unowned computed property in my opinion, since this is a property of the implementation of the underlying storage and not of the contract of the property itself. The latter is already captured wholly by giving the property an optional or IUO type, in my opinion.
Yay for implementing proposals during review and teasing out odd corner cases!
unowned var foo2: SomeClass { get set } // expected-warning {{ownership should not be specified in protocols and will be disallowed in future versions}} | ||
weak var foo3: Int? { get set } // expected-error {{'weak' may only be applied to class and class-bound protocol types, not 'Int'}} | ||
unowned var foo4: Int { get set } // expected-error {{'unowned' may only be applied to class and class-bound protocol types, not 'Int'}} | ||
} |
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.
Please add a trailing newline here
Objective-C does check that the declaration of the property matches how it was declared in the protocol, for a strong/weak mismatch but not a weak/unsafe-unretained mismatch. |
@jrose-apple While we're bike-shedding, there's a JIRA bug out there pointing out that 'unowned' and 'weak' lazy properties fail to type check with odd diagnostics. I wonder if these should also be banned. Can you think of reasonable semantics we could give them? The real reason it fails is that we try to form an optional type whose payload type is weak or unowned, which doesn't type check, but the diagnostic is really bad because the failure manifests when we check the underlying storage of the lazy property and not the lazy property itself. |
Well, it's certainly possible to lazily construct something on first access that someone else owns, but that'd definitely be weird and unusual. That seems like it's separate from Greg's work, though, and if it doesn't work at all today then it'd be fine to ban it properly without going through swift-evolution. |
@jrose-apple and @slavapestov, thank you both for the feedback. As you've identified, it seems there's at least two other cases where ownership keywords don't really work as expected, lazy properties and computed properties. I'm not sure what is best to do, I can expand the initial proposal to cover these two cases if you think that's best? When using lazy properties and unowned/weak I can't actually produce code that will compile, so I agree that might just need fixing regarding the warning/error messages the compiler produces and might be separate to the evolution process. For computed properties they are confusing when used with weak/unowned, as I'm not sure what you'd expect in this case:
The ownership keywords above are meaningless I believe, so a fix might fit nicely in the current SE proposal. I'm currently at a conference without my personal laptop so haven't been able to implement any of the changes you've identified above yet. |
Anyway, this seems good enough as a proof-of-concept for review. Agreed, Slava? |
@jrose-apple Agreed. While I do like the idea of addressing ownership keywords on computed properties and possibly lazy properties as part of implementing this proposal, it shouldn't block the swift-evolution discussion from moving forward. |
7fedcdb
to
b07eca7
Compare
I've pushed changes to address initial feedback. The error messages should be consistent with other existing related errors. Correct error message is used when using weak/unowned property in a protocol extension. I didn't do any changes regarding using ownership keywords with lazy or computed properties. I'll wait for guidance on if that's something I should put into the SE proposal. @jrose-apple and @slavapestov let me know if there's anything else you'd like to see added to this implementation or the SE proposal, thanks again for your help 👍 |
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.
Thanks, Greg. A few more comments since last time.
include/swift/AST/DeclContext.h
Outdated
@@ -255,6 +255,10 @@ class alignas(1 << DeclContextAlignInBits) DeclContext { | |||
/// EnumDecl, otherwise return null. | |||
EnumDecl *getAsEnumOrEnumExtensionContext() const; | |||
|
|||
/// If this DeclContext is a protocol and not an extension on a | |||
/// protocol, return the ProtocolDecl, otherwise return null. | |||
ProtocolDecl *getAsProtocolContext() const; |
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.
The LLVM casting infrastructure already gives us a way to do this: dyn_cast<ProtocolDecl>(declContext)
. So we don't need a new method.
lib/Sema/TypeCheckAttr.cpp
Outdated
@@ -2063,6 +2067,22 @@ void TypeChecker::checkOwnershipAttr(VarDecl *var, OwnershipAttr *attr) { | |||
|
|||
diagnose(var->getStartLoc(), D, (unsigned) ownershipKind, underlyingType); | |||
attr->setInvalid(); | |||
return; |
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.
This return
doesn't really make sense when we're about to explicitly check for invalid and return below. Either all of the conditions in this function should be changed (in which case you don't need the "else" in else if
), or you shouldn't worry about it. I'd lean towards the latter since it's less of a change from what's there.
|
||
extension P { | ||
weak var foo5: SomeClass? // expected-error {{extensions may not contain stored properties}} | ||
unowned var foo6: SomeClass // expected-error {{extensions may not contain stored properties}} |
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.
Please include some computed properties as well, since we've established that that's currently permitted.
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.
Thanks, I've added some tests below of what should still be permitted and not produce an error.
b07eca7
to
ef50ed6
Compare
SE-0186 has been accepted. |
@swift-ci test |
Build failed |
Build failed |
ef50ed6
to
c5d6e17
Compare
I've just rebased as I see some of the error messages were cleaned up recently. The tests pass on my machine now. |
@jrose-apple and @slavapestov now that the evolution proposal has been approved do you have any changes or additional feedback for this implementation? Thanks |
Seems fine to me! I'll merge if Slava has no objections. @swift-ci Please test |
@swift-ci Please test source compatibility |
@gspiers Do you mind submitting a PR to add this to CHANGELOG.md as well? Thanks! |
@slavapestov I'll create a PR Monday when I'm next near my computer. |
This is an implementation of a draft Swift Evolution proposal apple/swift-evolution#707 to remove support for 'weak' and 'unowned' keywords for property declarations in protocols.
As suggested on the evolution pull request this implementation warns in existing Swift 3 and 4 modes and offers a fixit to remove the keyword. For Swift 5 mode it errors and of course also offers a fixit.
I'm new to contributing to Swift, I'm happy to take feedback and any direction to improve the implementation or proposal.
Resolves SR-479.