-
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,18 @@ | ||
// RUN: %target-typecheck-verify-swift | ||
// RUN: %target-typecheck-verify-swift -parse-as-library | ||
// REQUIRES: OS=macosx | ||
|
||
// Allow referencing unavailable API in situations where the caller is marked unavailable in the same circumstances. | ||
|
||
@available(OSX, unavailable) | ||
func osx() {} // expected-note 2{{'osx()' has been explicitly marked unavailable here}} | ||
@discardableResult | ||
func osx() -> Int { return 0 } // expected-note * {{'osx()' has been explicitly marked unavailable here}} | ||
|
||
@available(OSXApplicationExtension, unavailable) | ||
func osx_extension() {} | ||
|
||
@available(OSX, unavailable) | ||
func osx_pair() -> (Int, Int) { return (0, 0) } // expected-note * {{'osx_pair()' has been explicitly marked unavailable here}} | ||
|
||
func call_osx_extension() { | ||
osx_extension() // OK; osx_extension is only unavailable if -application-extension is passed. | ||
} | ||
|
@@ -35,3 +39,84 @@ func osx_extension_call_osx_extension() { | |
func osx_extension_call_osx() { | ||
osx() // expected-error {{'osx()' is unavailable}} | ||
} | ||
|
||
@available(OSX, unavailable) | ||
var osx_init_osx = osx() // OK | ||
|
||
@available(OSXApplicationExtension, unavailable) | ||
var osx_extension_init_osx = osx() // expected-error {{'osx()' is unavailable}} | ||
|
||
@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 commentThe 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. |
||
@available(OSXApplicationExtension, unavailable) | ||
var osx_extension_inner_init_osx = { let inner_var = osx() } // expected-error 2 {{'osx()' is unavailable}} | ||
|
||
struct Outer { | ||
@available(OSX, unavailable) | ||
var osx_init_osx = osx() // OK | ||
|
||
@available(OSX, unavailable) | ||
lazy var osx_lazy_osx = osx() // OK | ||
|
||
@available(OSXApplicationExtension, unavailable) | ||
var osx_extension_init_osx = osx() // expected-error {{'osx()' is unavailable}} | ||
|
||
@available(OSXApplicationExtension, unavailable) | ||
var osx_extension_lazy_osx = osx() // expected-error {{'osx()' is unavailable}} | ||
|
||
@available(OSX, unavailable) | ||
var osx_init_multi1_osx = osx(), osx_init_multi2_osx = osx() // OK | ||
|
||
@available(OSXApplicationExtension, unavailable) | ||
var osx_extension_init_multi1_osx = osx(), osx_extension_init_multi2_osx = osx() // expected-error 2 {{'osx()' is unavailable}} | ||
|
||
@available(OSX, unavailable) | ||
var (osx_init_deconstruct1_osx, osx_init_deconstruct2_osx) = osx_pair() // OK | ||
|
||
@available(OSXApplicationExtension, unavailable) | ||
var (osx_extension_init_deconstruct1_osx, osx_extension_init_deconstruct2_osx) = osx_pair() // expected-error {{'osx_pair()' is unavailable}} | ||
|
||
@available(OSX, unavailable) | ||
var (_, osx_init_deconstruct2_only_osx) = osx_pair() // OK | ||
|
||
@available(OSXApplicationExtension, unavailable) | ||
var (_, osx_extension_init_deconstruct2_only_osx) = osx_pair() // expected-error {{'osx_pair()' is unavailable}} | ||
|
||
@available(OSX, unavailable) | ||
var (osx_init_deconstruct1_only_osx, _) = osx_pair() // OK | ||
|
||
@available(OSXApplicationExtension, unavailable) | ||
var (osx_extension_init_deconstruct1_only_osx, _) = osx_pair() // expected-error {{'osx_pair()' is unavailable}} | ||
|
||
@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. | ||
@available(OSXApplicationExtension, unavailable) | ||
var osx_extension_inner_init_osx = { let inner_var = osx() } // expected-error 2 {{'osx()' is unavailable}} | ||
} | ||
|
||
extension Outer { | ||
@available(OSX, unavailable) | ||
static var also_osx_init_osx = osx() // OK | ||
|
||
@available(OSXApplicationExtension, unavailable) | ||
static var also_osx_extension_init_osx = osx() // expected-error {{'osx()' is unavailable}} | ||
} | ||
|
||
@available(OSX, unavailable) | ||
extension Outer { | ||
static var outer_osx_init_osx = osx() // OK | ||
} | ||
|
||
@available(OSX, unavailable) | ||
struct NotOnOSX { | ||
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 commentThe 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 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, good call! |
||
var (_, osx_init_deconstruct2_only_osx) = osx_pair() // OK | ||
var (osx_init_deconstruct1_only_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.
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 theif (auto * IDC = ...)
block so it never callsContainsReferenceRange
if the reference range is invalid (and perhaps assert that fact inContainsReferenceRange
), or stick with this implementation.