Skip to content

Sema: Eliminate some piecemeal unavailability diagnostics #77236

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
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
4 changes: 1 addition & 3 deletions lib/Sema/TypeCheckAvailability.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2903,7 +2903,7 @@ void swift::diagnoseOverrideOfUnavailableDecl(ValueDecl *override,

/// Emit a diagnostic for references to declarations that have been
/// marked as unavailable, either through "unavailable" or "obsoleted:".
bool swift::diagnoseExplicitUnavailability(const ValueDecl *D, SourceRange R,
static bool diagnoseExplicitUnavailability(const ValueDecl *D, SourceRange R,
const ExportContext &Where,
const Expr *call,
DeclAvailabilityFlags Flags) {
Expand Down Expand Up @@ -4091,8 +4091,6 @@ bool swift::diagnoseDeclAvailability(const ValueDecl *D, SourceRange R,
const Expr *call,
const ExportContext &Where,
DeclAvailabilityFlags Flags) {
assert(!Where.isImplicit());

// Generic parameters are always available.
if (isa<GenericTypeParamDecl>(D))
return false;
Expand Down
7 changes: 0 additions & 7 deletions lib/Sema/TypeCheckAvailability.h
Original file line number Diff line number Diff line change
Expand Up @@ -311,13 +311,6 @@ void diagnoseOverrideOfUnavailableDecl(ValueDecl *override,
const ValueDecl *base,
const AvailableAttr *attr);

/// Emit a diagnostic for references to declarations that have been
/// marked as unavailable, either through "unavailable" or "obsoleted:".
bool diagnoseExplicitUnavailability(const ValueDecl *D, SourceRange R,
const ExportContext &Where,
const Expr *call,
DeclAvailabilityFlags Flags = std::nullopt);

/// Checks whether a declaration should be considered unavailable when referred
/// to in the given declaration context and availability context and, if so,
/// returns a result that describes the unmet availability requirements.
Expand Down
4 changes: 2 additions & 2 deletions lib/Sema/TypeCheckPattern.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ using namespace swift;
static EnumElementDecl *
extractEnumElement(DeclContext *DC, SourceLoc UseLoc,
const VarDecl *constant) {
ExportContext where = ExportContext::forFunctionBody(DC, UseLoc);
diagnoseExplicitUnavailability(constant, UseLoc, where, nullptr);
diagnoseDeclAvailability(constant, UseLoc, nullptr,
ExportContext::forFunctionBody(DC, UseLoc));

const FuncDecl *getter = constant->getAccessor(AccessorKind::Get);
if (!getter)
Expand Down
11 changes: 4 additions & 7 deletions lib/Sema/TypeCheckStorage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1202,13 +1202,10 @@ static Expr *buildStorageReference(AccessorDecl *accessor,
// Check for availability of wrappedValue.
if (accessor->getAccessorKind() == AccessorKind::Get ||
isYieldingDefaultNonmutatingAccessor(accessor->getAccessorKind())) {
if (wrappedValue->getAttrs().getUnavailable(ctx)) {
ExportContext where = ExportContext::forDeclSignature(var);
diagnoseExplicitUnavailability(
wrappedValue,
var->getAttachedPropertyWrappers()[i]->getRangeWithAt(),
where, nullptr);
}
diagnoseDeclAvailability(
wrappedValue,
var->getAttachedPropertyWrappers()[i]->getRangeWithAt(), nullptr,
ExportContext::forDeclSignature(accessor));
}

underlyingVars.push_back({ wrappedValue, isWrapperRefLValue });
Expand Down
1 change: 1 addition & 0 deletions test/SPI/spi-only-import-exportability.swift
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ public func implementationDetailsUser() {
public struct ClientStruct {
#if !SKIP_ERRORS
public var a: SPIOnlyStruct // expected-error {{cannot use struct 'SPIOnlyStruct' here; 'SPIOnlyImportedLib' was imported for SPI only}}
// expected-error@+1 {{cannot use property 'wrappedValue' here; 'SPIOnlyImportedLib' was imported for SPI only}}
@SPIOnlyPropertyWrapper(42) public var aWrapped: Any // expected-error {{cannot use generic struct 'SPIOnlyPropertyWrapper' as property wrapper here; 'SPIOnlyImportedLib' was imported for SPI only}}
#endif
@PublicPropertyWrapper(SPIOnlyStruct()) public var bWrapped: Any
Expand Down
3 changes: 3 additions & 0 deletions test/Sema/access-level-import-inlinable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ fileprivate import FileprivateLib
// expected-note@-1 2 {{generic struct 'FileprivateImportWrapper' imported as 'fileprivate' from 'FileprivateLib' here}}
// expected-note@-2 2 {{initializer 'init(wrappedValue:)' imported as 'fileprivate' from 'FileprivateLib' here}}
// expected-note@-3 2 {{protocol 'FileprivateImportProto' imported as 'fileprivate' from 'FileprivateLib' here}}
// expected-note@-4 2 {{property 'wrappedValue' imported as 'fileprivate' from 'FileprivateLib' here}}

private import PrivateLib
// expected-note@-1 10 {{struct 'PrivateImportType' imported as 'private' from 'PrivateLib' here}}
Expand Down Expand Up @@ -128,6 +129,7 @@ public struct GenericType<T, U> {}

@FileprivateImportWrapper // expected-error {{initializer 'init(wrappedValue:)' is fileprivate and cannot be referenced from an '@inlinable' function}}
// expected-error @-1 {{generic struct 'FileprivateImportWrapper' is fileprivate and cannot be referenced from an '@inlinable' function}}
// expected-error @-2 {{property 'wrappedValue' is fileprivate and cannot be referenced from an '@inlinable' function}}
var wrappedFileprivate: PublicImportType

let _: GenericType<PublicImportType, PublicImportType>
Expand Down Expand Up @@ -168,6 +170,7 @@ public struct GenericType<T, U> {}

@FileprivateImportWrapper // expected-error {{initializer 'init(wrappedValue:)' is fileprivate and cannot be referenced from an '@_alwaysEmitIntoClient' function}}
// expected-error @-1 {{generic struct 'FileprivateImportWrapper' is fileprivate and cannot be referenced from an '@_alwaysEmitIntoClient' function}}
// expected-error @-2 {{property 'wrappedValue' is fileprivate and cannot be referenced from an '@_alwaysEmitIntoClient' function}}
var wrappedFileprivate: PublicImportType

let _: GenericType<PublicImportType, PublicImportType>
Expand Down
1 change: 1 addition & 0 deletions test/Sema/implementation-only-import-in-decls.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ public struct TestInit {

public struct TestPropertyWrapper {
@BadWrapper public var BadProperty: Int // expected-error {{cannot use struct 'BadWrapper' as property wrapper here; 'BADLibrary' has been imported as implementation-only}}
// expected-error@-1 {{cannot use property 'wrappedValue' here; 'BADLibrary' has been imported as implementation-only}}
}

public protocol TestInherited: BadProto {} // expected-error {{cannot use protocol 'BadProto' here; 'BADLibrary' has been imported as implementation-only}}
Expand Down
1 change: 1 addition & 0 deletions test/Sema/missing-import-typealias.swift
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ public class InheritsFromClazzAlias: ClazzAlias {}
public func takesGeneric<T: ProtoAlias>(_ t: T) {}

public struct HasMembers {
// expected-warning@+3 {{cannot use property 'wrappedValue' here; 'Original' was not imported by this file}}
// expected-warning@+2 {{'WrapperAlias' aliases 'Original.Wrapper' and cannot be used as property wrapper here because 'Original' was not imported by this file; this is an error in the Swift 6 language mode}}
// expected-note@+1 {{The missing import of module 'Original' will be added implicitly}}
@WrapperAlias public var wrapped: Int
Expand Down
72 changes: 66 additions & 6 deletions test/Sema/property_wrapper_availability.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,33 @@ struct Available51Wrapper<T> {

@available(*, unavailable)
@propertyWrapper
struct UnavailableWrapper<T> { // expected-note 6 {{'UnavailableWrapper' has been explicitly marked unavailable here}}
struct UnavailableWrapper<T> { // expected-note 8 {{'UnavailableWrapper' has been explicitly marked unavailable here}}
var wrappedValue: T
}

@propertyWrapper
struct WrappedValueUnavailableOnMacOS<T> {
init(wrappedValue: T) { fatalError() }

@available(macOS, unavailable)
var wrappedValue: T { // expected-note 6 {{'wrappedValue' has been explicitly marked unavailable here}}
get { fatalError() }
set { fatalError() }
}
}

@propertyWrapper
struct WrappedValueAvailable51<T> {
init(wrappedValue: T) { fatalError() }

@available(macOS 51, *)
var wrappedValue: T {
get { fatalError() }
set { fatalError() }
}
}

struct AlwaysAvailableStruct { // expected-note 2 {{add @available attribute to enclosing struct}}
struct AlwaysAvailableStruct { // expected-note 3 {{add @available attribute to enclosing struct}}
@AlwaysAvailableWrapper var alwaysAvailableExplicit: S
@AlwaysAvailableWrapper var alwaysAvailableInferred = S()

Expand All @@ -31,6 +52,9 @@ struct AlwaysAvailableStruct { // expected-note 2 {{add @available attribute to

@UnavailableWrapper var unavailableExplicit: S // expected-error {{'UnavailableWrapper' is unavailable}}
@UnavailableWrapper var unavailableInferred = S() // expected-error {{'UnavailableWrapper' is unavailable}}

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

@available(macOS 51, *)
Expand All @@ -43,6 +67,9 @@ struct Available51Struct {

@UnavailableWrapper var unavailableExplicit: S // expected-error {{'UnavailableWrapper' is unavailable}}
@UnavailableWrapper var unavailableInferred = S() // expected-error {{'UnavailableWrapper' is unavailable}}

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

@available(*, unavailable)
Expand All @@ -55,24 +82,57 @@ struct UnavailableStruct {

@UnavailableWrapper var unavailableExplicit: S
@UnavailableWrapper var unavailableInferred = S()

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

func alwaysAvailableFunc( // expected-note {{add @available attribute to enclosing global function}}
@available(macOS, unavailable)
struct UnavailableOnMacOSStruct {
@AlwaysAvailableWrapper var alwaysAvailableExplicit: S
@AlwaysAvailableWrapper var alwaysAvailableInferred = S()

@Available51Wrapper var available51Explicit: S // expected-error {{'Available51Wrapper' is only available in macOS 51 or newer}}
@Available51Wrapper var available51Inferred = S() // expected-error {{'Available51Wrapper' is only available in macOS 51 or newer}}

@UnavailableWrapper var unavailableExplicit: S // expected-error {{'UnavailableWrapper' is unavailable}}
@UnavailableWrapper var unavailableInferred = S() // expected-error {{'UnavailableWrapper' is unavailable}}

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

func alwaysAvailableFunc( // expected-note 2 {{add @available attribute to enclosing global function}}
@AlwaysAvailableWrapper _ alwaysAvailable: S,
@Available51Wrapper _ available51: S, // expected-error {{'Available51Wrapper' is only available in macOS 51 or newer}}
@UnavailableWrapper _ unavailable: S // expected-error {{'UnavailableWrapper' is unavailable}}
@UnavailableWrapper _ unavailable: S, // expected-error {{'UnavailableWrapper' is unavailable}}
@WrappedValueUnavailableOnMacOS _ unavailableWrappedValue: S, // expected-error {{'wrappedValue' is unavailable in macOS}}
@WrappedValueAvailable51 _ wrappedValueAavailable51: S // expected-error {{'wrappedValue' is only available in macOS 51 or newer}}
) {}

@available(macOS 51, *)
func available51Func(
@AlwaysAvailableWrapper _ alwaysAvailable: S,
@Available51Wrapper _ available51: S,
@UnavailableWrapper _ unavailable: S // expected-error {{'UnavailableWrapper' is unavailable}}
@UnavailableWrapper _ unavailable: S, // expected-error {{'UnavailableWrapper' is unavailable}}
@WrappedValueUnavailableOnMacOS _ unavailableWrappedValue: S, // expected-error {{'wrappedValue' is unavailable in macOS}}
@WrappedValueAvailable51 _ wrappedValueAavailable51: S
) {}

@available(*, unavailable)
func unavailableFunc(
@AlwaysAvailableWrapper _ alwaysAvailable: S,
@Available51Wrapper _ available51: S,
@UnavailableWrapper _ unavailable: S
@UnavailableWrapper _ unavailable: S,
@WrappedValueUnavailableOnMacOS _ unavailableWrappedValue: S, // expected-error {{'wrappedValue' is unavailable in macOS}}
@WrappedValueAvailable51 _ wrappedValueAavailable51: S // expected-error {{'wrappedValue' is only available in macOS 51 or newer}}
) {}

@available(macOS, unavailable)
func unavailableOnMacOSFunc(
@AlwaysAvailableWrapper _ alwaysAvailable: S,
@Available51Wrapper _ available51: S,
@UnavailableWrapper _ unavailable: S,
@WrappedValueUnavailableOnMacOS _ unavailableWrappedValue: S,
@WrappedValueAvailable51 _ wrappedValueAavailable51: S // expected-error {{'wrappedValue' is only available in macOS 51 or newer}}
) {}
8 changes: 8 additions & 0 deletions test/Sema/property_wrapper_parameter_invalid.swift
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ struct Wrapper<T> { // expected-note 3 {{type declared here}}
self.wrappedValue = projectedValue.value
}

// expected-note@+1 {{property 'wrappedValue' is not '@usableFromInline' or public}}
var wrappedValue: T
var projectedValue: Projection<T> { Projection(value: wrappedValue) }
}
Expand Down Expand Up @@ -127,6 +128,7 @@ enum E {
// expected-error@+1 {{function cannot be declared public because its parameter uses an internal API wrapper type}}
public func f1(@Wrapper value: Int) {}

// expected-error@+4 {{property 'wrappedValue' is internal and cannot be referenced from an '@inlinable' function}}
// expected-error@+3 {{generic struct 'Wrapper' is internal and cannot be referenced from an '@inlinable' function}}
// expected-error@+2 {{the parameter API wrapper of a '@usableFromInline' function must be '@usableFromInline' or public}}
// expected-error@+1 {{initializer 'init(wrappedValue:)' is internal and cannot be referenced from an '@inlinable' function}}
Expand Down Expand Up @@ -155,6 +157,7 @@ public struct PublicWrapper<T> {
// expected-note@+2 2 {{generic struct 'PackageWrapper' is not '@usableFromInline' or public}}
@propertyWrapper
package struct PackageWrapper<T> { // expected-note 3 {{type declared here}}
// expected-note@+1 2 {{property 'wrappedValue' is not '@usableFromInline' or public}}
package var wrappedValue: T

// expected-note@+1 2 {{initializer 'init(wrappedValue:)' is not '@usableFromInline' or public}}
Expand All @@ -164,6 +167,7 @@ package struct PackageWrapper<T> { // expected-note 3 {{type declared here}}
// expected-note@+2 2 {{generic struct 'InternalWrapper' is not '@usableFromInline' or public}}
@propertyWrapper
struct InternalWrapper<T> { // expected-note 3 {{type declared here}}
// expected-note@+1 2 {{property 'wrappedValue' is not '@usableFromInline' or public}}
var wrappedValue: T

// expected-note@+1 2 {{initializer 'init(wrappedValue:)' is not '@usableFromInline' or public}}
Expand Down Expand Up @@ -200,20 +204,24 @@ public func testComposition2pkg(@PackageWrapper @PublicWrapper value: Int) {}
// Okay because `PackageWrapper` is implementation-detail.
@usableFromInline func testComposition4pkg(@PackageWrapper @PublicWrapper value: Int) {}

// expected-error@+4 {{property 'wrappedValue' is internal and cannot be referenced from an '@inlinable' function}}
// expected-error@+3 {{generic struct 'InternalWrapper' is internal and cannot be referenced from an '@inlinable' function}}
// expected-error@+2 {{the parameter API wrapper of a '@usableFromInline' function must be '@usableFromInline' or public}}
// expected-error@+1 {{initializer 'init(wrappedValue:)' is internal and cannot be referenced from an '@inlinable' function}}
@inlinable func testComposition5(@PublicWrapper @InternalWrapper value: Int) {}

// expected-error@+3 {{property 'wrappedValue' is internal and cannot be referenced from an '@inlinable' function}}
// expected-error@+2 {{generic struct 'InternalWrapper' is internal and cannot be referenced from an '@inlinable' function}}
// expected-error@+1 {{initializer 'init(wrappedValue:)' is internal and cannot be referenced from an '@inlinable' function}}
@inlinable func testComposition6(@InternalWrapper @PublicWrapper value: Int) {}

// expected-error@+4 {{property 'wrappedValue' is package and cannot be referenced from an '@inlinable' function}}
// expected-error@+3 {{generic struct 'PackageWrapper' is package and cannot be referenced from an '@inlinable' function}}
// expected-error@+2 {{the parameter API wrapper of a '@usableFromInline' function must be '@usableFromInline' or public}}
// expected-error@+1 {{initializer 'init(wrappedValue:)' is package and cannot be referenced from an '@inlinable' function}}
@inlinable func testComposition5pkg(@PublicWrapper @PackageWrapper value: Int) {}

// expected-error@+3 {{property 'wrappedValue' is package and cannot be referenced from an '@inlinable' function}}
// expected-error@+2 {{generic struct 'PackageWrapper' is package and cannot be referenced from an '@inlinable' function}}
// expected-error@+1 {{initializer 'init(wrappedValue:)' is package and cannot be referenced from an '@inlinable' function}}
@inlinable func testComposition6pkg(@PackageWrapper @PublicWrapper value: Int) {}
Expand Down
3 changes: 2 additions & 1 deletion test/Sema/spi-in-decls.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public struct IntLike: ExpressibleByIntegerLiteral, Equatable { // expected-note
@_spi(X)
@propertyWrapper
public struct BadWrapper { // expected-note {{type declared here}}
public var wrappedValue: Int
public var wrappedValue: Int // expected-note {{type declared here}}
public init(wrappedValue: Int) {
self.wrappedValue = wrappedValue
}
Expand Down Expand Up @@ -87,6 +87,7 @@ public struct TestInit {

public struct TestPropertyWrapper {
@BadWrapper public var BadProperty: Int // expected-error {{cannot use struct 'BadWrapper' as property wrapper here; it is SPI}}
// expected-error@-1 {{cannot use property 'wrappedValue' here; it is SPI}}
}

public protocol TestInherited: BadProto {} // expected-error {{cannot use protocol 'BadProto' here; it is SPI}}
Expand Down
9 changes: 8 additions & 1 deletion test/decl/var/property_wrappers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -961,7 +961,7 @@ struct Observable<Value> {
}

@available(*, unavailable, message: "must be in a class")
var wrappedValue: Value { // expected-note{{'wrappedValue' has been explicitly marked unavailable here}}
var wrappedValue: Value { // expected-note 2{{'wrappedValue' has been explicitly marked unavailable here}}
get { fatalError("called wrappedValue getter") }
set { fatalError("called wrappedValue setter") }
}
Expand All @@ -985,6 +985,13 @@ struct MyObservedValueType {
var observedProperty = 17
}

func takesObservable(@Observable _ observable: Int) {} // expected-error{{'wrappedValue' is unavailable: must be in a class}}

class MyObservedClass {
@Observable
var observedProperty = 17
}

// ---------------------------------------------------------------------------
// Miscellaneous bugs
// ---------------------------------------------------------------------------
Expand Down