Skip to content

Sema: Relax availability checking in universally unavailable contexts #78077

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
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions lib/Sema/TypeCheckAvailability.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -346,17 +346,17 @@ static bool computeContainedByDeploymentTarget(AvailabilityScope *scope,
static bool isInsideCompatibleUnavailableDeclaration(
const Decl *D, AvailabilityContext availabilityContext,
const AvailableAttr *attr) {
auto referencedPlatform = availabilityContext.getUnavailablePlatformKind();
if (!referencedPlatform)
auto contextPlatform = availabilityContext.getUnavailablePlatformKind();
if (!contextPlatform)
return false;

if (!attr->isUnconditionallyUnavailable())
return false;

// Refuse calling universally unavailable functions from unavailable code,
// but allow the use of types.
PlatformKind platform = attr->getPlatform();
if (platform == PlatformKind::none && !attr->isForEmbedded() &&
PlatformKind declPlatform = attr->getPlatform();
if (declPlatform == PlatformKind::none && !attr->isForEmbedded() &&
!isa<TypeDecl>(D) && !isa<ExtensionDecl>(D))
return false;

Expand All @@ -365,8 +365,9 @@ static bool isInsideCompatibleUnavailableDeclaration(
if (attr->isForEmbedded())
return availabilityContext.isUnavailableInEmbedded();

return (*referencedPlatform == platform ||
inheritsAvailabilityFromPlatform(platform, *referencedPlatform));
return (*contextPlatform == PlatformKind::none ||
*contextPlatform == declPlatform ||
inheritsAvailabilityFromPlatform(declPlatform, *contextPlatform));
}

const AvailableAttr *
Expand Down
8 changes: 4 additions & 4 deletions test/Sema/property_wrapper_availability.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ struct WrappedValueUnavailableOnMacOS<T> {
init(wrappedValue: T) { fatalError() }

@available(macOS, unavailable)
var wrappedValue: T { // expected-note 9 {{'wrappedValue' has been explicitly marked unavailable here}}
var wrappedValue: T { // expected-note 6 {{'wrappedValue' has been explicitly marked unavailable here}}
get { fatalError() }
set { fatalError() }
}
Expand Down Expand Up @@ -98,7 +98,7 @@ struct UnavailableStruct {
@UnavailableWrapper var unavailableExplicit: S
@UnavailableWrapper var unavailableInferred = S()

@WrappedValueUnavailableOnMacOS var unavailableWrappedValue: S // expected-error {{'wrappedValue' is unavailable in macOS}}
@WrappedValueUnavailableOnMacOS var unavailableWrappedValue: S
@WrappedValueAvailable51 var wrappedValueAavailable51: S // expected-error {{'wrappedValue' is only available in macOS 51 or newer}}
}

Expand Down Expand Up @@ -159,14 +159,14 @@ func unavailableFunc(
@Available51Wrapper _ available51: S,
@DeprecatedWrapper _ deprecated: S,
@UnavailableWrapper _ unavailable: S,
@WrappedValueUnavailableOnMacOS _ unavailableWrappedValue: S, // expected-error {{'wrappedValue' is unavailable in macOS}}
@WrappedValueUnavailableOnMacOS _ unavailableWrappedValue: S,
@WrappedValueAvailable51 _ wrappedValueAavailable51: S // expected-error {{'wrappedValue' is only available in macOS 51 or newer}}
) {
@AlwaysAvailableWrapper var alwaysAvailableLocal = S()
@Available51Wrapper var available51Local = S()
@DeprecatedWrapper var deprecatedLocal = S()
@UnavailableWrapper var unavailableLocal = S()
@WrappedValueUnavailableOnMacOS var unavailableWrappedValueLocal = S() // expected-error {{'wrappedValue' is unavailable}}
@WrappedValueUnavailableOnMacOS var unavailableWrappedValueLocal = S()
@WrappedValueAvailable51 var wrappedValueAavailable51 = S() // expected-error {{'wrappedValue' is only available in macOS 51 or newer}}
}

Expand Down
36 changes: 18 additions & 18 deletions test/attr/attr_availability_transitive_osx.swift
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,8 @@ func never_available_func(
never() // expected-error {{'never()' is unavailable}}
osx_future() // expected-error {{'osx_future()' is only available in macOS 99 or newer}}
// expected-note@-1 {{add 'if #available' version check}}
osx() // expected-error {{'osx()' is unavailable}}
osx_ios() // expected-error {{'osx_ios()' is unavailable}}
osx()
osx_ios()
osx_extension()
}

Expand Down Expand Up @@ -160,8 +160,8 @@ var never_var: (
always(),
never(), // expected-error {{'never()' is unavailable}}
osx_future(), // expected-error {{'osx_future()' is only available in macOS 99 or newer}}
osx(), // expected-error {{'osx()' is unavailable}}
osx_ios(), // expected-error {{'osx_ios()' is unavailable}}
osx(),
osx_ios(),
osx_extension()
)

Expand Down Expand Up @@ -219,8 +219,8 @@ struct NeverAvailableContainer { // expected-note 2 {{'NeverAvailableContainer'
let always_var: AlwaysAvailabile = always()
let never_var: NeverAvailable = never() // expected-error {{'never()' is unavailable}}
let osx_future_var: OSXFutureAvailable = osx_future() // expected-error {{'osx_future()' is only available in macOS 99 or newer}}
let osx_var: OSXUnavailable = osx() // expected-error {{'osx()' is unavailable}}
let osx_ios_var: MultiPlatformUnavailable = osx_ios() // expected-error {{'osx_ios()' is unavailable}}
let osx_var: OSXUnavailable = osx()
let osx_ios_var: MultiPlatformUnavailable = osx_ios()
let osx_extension_var: OSXAppExtensionsUnavailable = osx_extension()
}

Expand Down Expand Up @@ -303,8 +303,8 @@ extension ExtendMe {
never() // expected-error {{'never()' is unavailable}}
osx_future() // expected-error {{'osx_future()' is only available in macOS 99 or newer}}
// expected-note@-1 {{add 'if #available' version check}}
osx() // expected-error {{'osx()' is unavailable}}
osx_ios() // expected-error {{'osx_ios()' is unavailable}}
osx()
osx_ios()
osx_extension()
}

Expand All @@ -321,8 +321,8 @@ extension ExtendMe {
never() // expected-error {{'never()' is unavailable}}
osx_future() // expected-error {{'osx_future()' is only available in macOS 99 or newer}}
// expected-note@-1 {{add 'if #available' version check}}
osx() // expected-error {{'osx()' is unavailable}}
osx_ios() // expected-error {{'osx_ios()' is unavailable}}
osx()
osx_ios()
osx_extension()
}

Expand All @@ -339,8 +339,8 @@ extension ExtendMe {
never() // expected-error {{'never()' is unavailable}}
osx_future() // expected-error {{'osx_future()' is only available in macOS 99 or newer}}
// expected-note@-1 {{add 'if #available' version check}}
osx() // expected-error {{'osx()' is unavailable}}
osx_ios() // expected-error {{'osx_ios()' is unavailable}}
osx()
osx_ios()
osx_extension()
}

Expand All @@ -357,8 +357,8 @@ extension ExtendMe {
never() // expected-error {{'never()' is unavailable}}
osx_future() // expected-error {{'osx_future()' is only available in macOS 99 or newer}}
// expected-note@-1 {{add 'if #available' version check}}
osx() // expected-error {{'osx()' is unavailable}}
osx_ios() // expected-error {{'osx_ios()' is unavailable}}
osx()
osx_ios()
osx_extension()
}
}
Expand Down Expand Up @@ -400,8 +400,8 @@ extension ExtendMe {
never() // expected-error {{'never()' is unavailable}}
osx_future() // expected-error {{'osx_future()' is only available in macOS 99 or newer}}
// expected-note@-1 {{add 'if #available' version check}}
osx() // expected-error {{'osx()' is unavailable}}
osx_ios() // expected-error {{'osx_ios()' is unavailable}}
osx()
osx_ios()
osx_extension()
}

Expand Down Expand Up @@ -479,8 +479,8 @@ extension ExtendMe { // expected-note * {{add @available attribute to enclosing
never() // expected-error {{'never()' is unavailable}}
osx_future() // expected-error {{'osx_future()' is only available in macOS 99 or newer}}
// expected-note@-1 {{add 'if #available' version check}}
osx() // expected-error {{'osx()' is unavailable}}
osx_ios() // expected-error {{'osx_ios()' is unavailable}}
osx()
osx_ios()
osx_extension()
}

Expand Down
36 changes: 18 additions & 18 deletions test/attr/attr_availability_transitive_osx_appext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ func never_available_func(
_: OSXAppExtensionsUnavailable
) {
never() // expected-error {{'never()' is unavailable}}
osx() // expected-error {{'osx()' is unavailable}}
osx_extension() // expected-error {{'osx_extension()' is unavailable in application extensions for macOS}}
osx()
osx_extension()
}

@available(OSX, unavailable)
Expand Down Expand Up @@ -94,8 +94,8 @@ var never_var: (
OSXAppExtensionsUnavailable
) = (
never(), // expected-error {{'never()' is unavailable}}
osx(), // expected-error {{'osx()' is unavailable}}
osx_extension() // expected-error {{'osx_extension()' is unavailable in application extensions for macOS}}
osx(),
osx_extension()
)

@available(OSX, unavailable)
Expand Down Expand Up @@ -134,8 +134,8 @@ struct AlwaysAvailabileContainer {
@available(*, unavailable)
struct NeverAvailableContainer { // expected-note {{'NeverAvailableContainer' has been explicitly marked unavailable here}}
let never_var: NeverAvailable = never() // expected-error {{'never()' is unavailable}}
let osx_var: OSXUnavailable = osx() // expected-error {{'osx()' is unavailable}}
let osx_extension_var: OSXAppExtensionsUnavailable = osx_extension() // expected-error {{'osx_extension()' is unavailable in application extensions for macOS}}
let osx_var: OSXUnavailable = osx()
let osx_extension_var: OSXAppExtensionsUnavailable = osx_extension()
}

@available(OSX, unavailable)
Expand Down Expand Up @@ -201,8 +201,8 @@ extension ExtendMe {
_: OSXAppExtensionsUnavailable
) {
never() // expected-error {{'never()' is unavailable}}
osx() // expected-error {{'osx()' is unavailable}}
osx_extension() // expected-error {{'osx_extension()' is unavailable in application extensions for macOS}}
osx()
osx_extension()
}

@available(*, unavailable)
Expand All @@ -212,8 +212,8 @@ extension ExtendMe {
_: OSXAppExtensionsUnavailable
) {
never() // expected-error {{'never()' is unavailable}}
osx() // expected-error {{'osx()' is unavailable}}
osx_extension() // expected-error {{'osx_extension()' is unavailable in application extensions for macOS}}
osx()
osx_extension()
}

@available(OSX, unavailable)
Expand All @@ -223,8 +223,8 @@ extension ExtendMe {
_: OSXAppExtensionsUnavailable
) {
never() // expected-error {{'never()' is unavailable}}
osx() // expected-error {{'osx()' is unavailable}}
osx_extension() // expected-error {{'osx_extension()' is unavailable in application extensions for macOS}}
osx()
osx_extension()
}

@available(OSXApplicationExtension, unavailable)
Expand All @@ -234,8 +234,8 @@ extension ExtendMe {
_: OSXAppExtensionsUnavailable
) {
never() // expected-error {{'never()' is unavailable}}
osx() // expected-error {{'osx()' is unavailable}}
osx_extension() // expected-error {{'osx_extension()' is unavailable in application extensions for macOS}}
osx()
osx_extension()
}
}

Expand Down Expand Up @@ -263,8 +263,8 @@ extension ExtendMe {
_: OSXAppExtensionsUnavailable
) {
never() // expected-error {{'never()' is unavailable}}
osx() // expected-error {{'osx()' is unavailable}}
osx_extension() // expected-error {{'osx_extension()' is unavailable in application extensions for macOS}}
osx()
osx_extension()
}

@available(OSX, unavailable)
Expand Down Expand Up @@ -314,8 +314,8 @@ extension ExtendMe {
_: OSXAppExtensionsUnavailable
) {
never() // expected-error {{'never()' is unavailable}}
osx() // expected-error {{'osx()' is unavailable}}
osx_extension() // expected-error {{'osx_extension()' is unavailable in application extensions for macOS}}
osx()
osx_extension()
}

@available(OSX, unavailable)
Expand Down
43 changes: 39 additions & 4 deletions test/type/opaque_availability.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,47 @@ func alwaysOpaque() -> some P { return X() } // expected-only-available-error{{'
@available(SwiftStdlib 5.1, *)
func sometimesOpaque() -> some P { return X() }

struct NotP {}
struct NeverConformsToP {}

@available(*, unavailable)
extension NotP: P {} // expected-note {{conformance of 'NotP' to 'P' has been explicitly marked unavailable here}}
extension NeverConformsToP: P {} // expected-note 2 {{conformance of 'NeverConformsToP' to 'P' has been explicitly marked unavailable here}}

@available(SwiftStdlib 5.1, *)
func requireP() -> some P {
NotP() // expected-error {{conformance of 'NotP' to 'P' is unavailable}}
struct Outer {
func returnsNeverConformsToP() -> some P {
NeverConformsToP() // expected-error {{conformance of 'NeverConformsToP' to 'P' is unavailable}}
}

@available(macOS, unavailable)
func returnsNeverConformsToP_macOSUnavailable() -> some P {
NeverConformsToP() // expected-error {{conformance of 'NeverConformsToP' to 'P' is unavailable}}
}

@available(*, unavailable)
func returnsNeverConformsToP_alwaysUnavailable() -> some P {
NeverConformsToP()
}
}

struct ConformsToPExeceptOnMacOS {}

@available(macOS, unavailable)
extension ConformsToPExeceptOnMacOS: P {} // expected-note {{conformance of 'ConformsToPExeceptOnMacOS' to 'P' has been explicitly marked unavailable here}}

@available(SwiftStdlib 5.1, *)
extension Outer {
func returnsConformsToPExeceptOnMacOS() -> some P {
ConformsToPExeceptOnMacOS() // expected-error {{conformance of 'ConformsToPExeceptOnMacOS' to 'P' is unavailable in macOS}}
}

@available(macOS, unavailable)
func returnsConformsToPExeceptOnMacOS_macOSUnavailable() -> some P {
ConformsToPExeceptOnMacOS()
}

@available(*, unavailable)
func returnsConformsToPExeceptOnMacOS_alwaysUnavailable() -> some P {
ConformsToPExeceptOnMacOS()
}

}