-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Extend transitive availability checking to initial value expressions (better version) #22460
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
Extend transitive availability checking to initial value expressions (better version) #22460
Conversation
When a Decl is also a DeclContext, these two concepts are identical, and we rely on that throughout the compiler. No functionality change; we appear to already be doing this correctly.
@swift-ci Please test |
@swift-ci Please test source compatibility |
@swift-ci Please smoke test compiler performance |
@available(OSX, unavailable) | ||
var osx_inner_init_osx = { let inner_var = osx() } // OK | ||
|
||
// FIXME: I'm not sure why this produces two errors instead of just one. |
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 it's because someone is not skipping multi-statement closures somewhere, so the body of the closure is visited again. Just a guess though.
var osx_init_osx = osx() // OK | ||
lazy var osx_lazy_osx = osx() // OK | ||
var osx_init_multi1_osx = osx(), osx_init_multi2_osx = osx() // OK | ||
var (osx_init_deconstruct1_osx, osx_init_deconstruct2_osx) = osx_pair() // OK |
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.
Just to be sure can you also test a few cases involving patterns like var (foo, _) = ...
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.
Oh, good call!
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.
My comments are optional.
@@ -856,27 +857,41 @@ static Optional<ASTNode> findInnermostAncestor( | |||
static const Decl *findContainingDeclaration(SourceRange ReferenceRange, | |||
const DeclContext *ReferenceDC, | |||
const SourceManager &SM) { | |||
if (const Decl *D = ReferenceDC->getInnermostDeclarationDeclContext()) | |||
auto ContainsReferenceRange = [&](const Decl *D) -> bool { | |||
if (ReferenceRange.isInvalid()) |
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.
Could you remove this check from the find_if
loop by moving the early return later in the function up?
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.
That changes behavior slightly, since in the top-level case it means we return nullptr
and in the decl case we return the decl.
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.
Oh, you're right. I think you could still test the range's validity once before calling find_if
, but that might not be worth the trouble.
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 guess I can remove the other check, even though that makes things slightly less efficient. What do you think?
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 don't think you should remove the other check. You should either put an if (ReferenceRange.isInvalid()) return D;
before the if (auto * IDC = ...)
block so it never calls ContainsReferenceRange
if the reference range is invalid (and perhaps assert that fact in ContainsReferenceRange
), or stick with this implementation.
lib/Sema/TypeCheckAvailability.cpp
Outdated
DC = DC->getParent(); | ||
} while (DC); | ||
DC = D->getDeclContext(); | ||
} while (true); |
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 this become a for(;;)
loop? If not, can it at least be a while(true)
loop instead of do {} while(true)
so its lack of natural termination is obvious from the start?
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.
Oh. Right.
Because initial value expressions aren't actually considered /within/ the VarDecl or PatternBindingDecl they're initializing, the existing logic to search for availability attributes wasn't kicking in, leading to errors when a conditionally-unavailable value was used in an initial value expression for a conditionally-unavailable binding. Fix this by walking the enclosing type or extension to find the appropriate PatternBindingDecl. https://bugs.swift.org/browse/SR-9867
As near as I can tell, this was always going to start with DeclarationToSearch and then end up with DeclarationToSearch, since it's already a declaration (and we already checked for null earlier). No test changes observed either.
41a3374
to
19c1765
Compare
@swift-ci Please smoke test |
@jrose-apple CI is currently offline. |
@swift-ci Please smoke test |
3 similar comments
@swift-ci Please smoke test |
@swift-ci Please smoke test |
@swift-ci Please smoke test |
@swift-ci Please smoke test macOS |
Because initial value expressions aren't actually considered within the VarDecl or PatternBindingDecl they're initializing, the existing logic to search for availability attributes wasn't kicking in, leading to errors when a conditionally-unavailable value was used in an initial value expression for a conditionally-unavailable binding. Fix this by walking the enclosing type or extension to find the appropriate PatternBindingDecl.
SR-9867 / rdar://problem/47852718
@brentdax caught some missing cases in the previous version (#22438); this is better.