Skip to content

Commit 99eeea1

Browse files
committed
Sema: Fully check the availability of wrappedValue.
Call `checkDeclarationAvailability()`, instead of just diagnosing unavailability.
1 parent 4069518 commit 99eeea1

File tree

6 files changed

+87
-24
lines changed

6 files changed

+87
-24
lines changed

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2903,7 +2903,7 @@ void swift::diagnoseOverrideOfUnavailableDecl(ValueDecl *override,
29032903

29042904
/// Emit a diagnostic for references to declarations that have been
29052905
/// marked as unavailable, either through "unavailable" or "obsoleted:".
2906-
bool swift::diagnoseExplicitUnavailability(const ValueDecl *D, SourceRange R,
2906+
static bool diagnoseExplicitUnavailability(const ValueDecl *D, SourceRange R,
29072907
const ExportContext &Where,
29082908
const Expr *call,
29092909
DeclAvailabilityFlags Flags) {
@@ -4091,8 +4091,6 @@ bool swift::diagnoseDeclAvailability(const ValueDecl *D, SourceRange R,
40914091
const Expr *call,
40924092
const ExportContext &Where,
40934093
DeclAvailabilityFlags Flags) {
4094-
assert(!Where.isImplicit());
4095-
40964094
// Generic parameters are always available.
40974095
if (isa<GenericTypeParamDecl>(D))
40984096
return false;

lib/Sema/TypeCheckAvailability.h

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -311,13 +311,6 @@ void diagnoseOverrideOfUnavailableDecl(ValueDecl *override,
311311
const ValueDecl *base,
312312
const AvailableAttr *attr);
313313

314-
/// Emit a diagnostic for references to declarations that have been
315-
/// marked as unavailable, either through "unavailable" or "obsoleted:".
316-
bool diagnoseExplicitUnavailability(const ValueDecl *D, SourceRange R,
317-
const ExportContext &Where,
318-
const Expr *call,
319-
DeclAvailabilityFlags Flags = std::nullopt);
320-
321314
/// Checks whether a declaration should be considered unavailable when referred
322315
/// to in the given declaration context and availability context and, if so,
323316
/// returns a result that describes the unmet availability requirements.

lib/Sema/TypeCheckStorage.cpp

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1202,13 +1202,10 @@ static Expr *buildStorageReference(AccessorDecl *accessor,
12021202
// Check for availability of wrappedValue.
12031203
if (accessor->getAccessorKind() == AccessorKind::Get ||
12041204
isYieldingDefaultNonmutatingAccessor(accessor->getAccessorKind())) {
1205-
if (wrappedValue->getAttrs().getUnavailable(ctx)) {
1206-
ExportContext where = ExportContext::forDeclSignature(var);
1207-
diagnoseExplicitUnavailability(
1208-
wrappedValue,
1209-
var->getAttachedPropertyWrappers()[i]->getRangeWithAt(),
1210-
where, nullptr);
1211-
}
1205+
diagnoseDeclAvailability(
1206+
wrappedValue,
1207+
var->getAttachedPropertyWrappers()[i]->getRangeWithAt(), nullptr,
1208+
ExportContext::forDeclSignature(accessor));
12121209
}
12131210

12141211
underlyingVars.push_back({ wrappedValue, isWrapperRefLValue });

test/Sema/property_wrapper_availability.swift

Lines changed: 66 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,33 @@ struct Available51Wrapper<T> {
1717

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

24+
@propertyWrapper
25+
struct WrappedValueUnavailableOnMacOS<T> {
26+
init(wrappedValue: T) { fatalError() }
27+
28+
@available(macOS, unavailable)
29+
var wrappedValue: T { // expected-note 6 {{'wrappedValue' has been explicitly marked unavailable here}}
30+
get { fatalError() }
31+
set { fatalError() }
32+
}
33+
}
34+
35+
@propertyWrapper
36+
struct WrappedValueAvailable51<T> {
37+
init(wrappedValue: T) { fatalError() }
38+
39+
@available(macOS 51, *)
40+
var wrappedValue: T {
41+
get { fatalError() }
42+
set { fatalError() }
43+
}
44+
}
2445

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

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

3253
@UnavailableWrapper var unavailableExplicit: S // expected-error {{'UnavailableWrapper' is unavailable}}
3354
@UnavailableWrapper var unavailableInferred = S() // expected-error {{'UnavailableWrapper' is unavailable}}
55+
56+
@WrappedValueUnavailableOnMacOS var unavailableWrappedValue: S // expected-error {{'wrappedValue' is unavailable in macOS}}
57+
@WrappedValueAvailable51 var wrappedValueAavailable51: S // expected-error {{'wrappedValue' is only available in macOS 51 or newer}}
3458
}
3559

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

4468
@UnavailableWrapper var unavailableExplicit: S // expected-error {{'UnavailableWrapper' is unavailable}}
4569
@UnavailableWrapper var unavailableInferred = S() // expected-error {{'UnavailableWrapper' is unavailable}}
70+
71+
@WrappedValueUnavailableOnMacOS var unavailableWrappedValue: S // expected-error {{'wrappedValue' is unavailable in macOS}}
72+
@WrappedValueAvailable51 var wrappedValueAavailable51: S
4673
}
4774

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

5683
@UnavailableWrapper var unavailableExplicit: S
5784
@UnavailableWrapper var unavailableInferred = S()
85+
86+
@WrappedValueUnavailableOnMacOS var unavailableWrappedValue: S // expected-error {{'wrappedValue' is unavailable in macOS}}
87+
@WrappedValueAvailable51 var wrappedValueAavailable51: S // expected-error {{'wrappedValue' is only available in macOS 51 or newer}}
5888
}
5989

60-
func alwaysAvailableFunc( // expected-note {{add @available attribute to enclosing global function}}
90+
@available(macOS, unavailable)
91+
struct UnavailableOnMacOSStruct {
92+
@AlwaysAvailableWrapper var alwaysAvailableExplicit: S
93+
@AlwaysAvailableWrapper var alwaysAvailableInferred = S()
94+
95+
@Available51Wrapper var available51Explicit: S // expected-error {{'Available51Wrapper' is only available in macOS 51 or newer}}
96+
@Available51Wrapper var available51Inferred = S() // expected-error {{'Available51Wrapper' is only available in macOS 51 or newer}}
97+
98+
@UnavailableWrapper var unavailableExplicit: S // expected-error {{'UnavailableWrapper' is unavailable}}
99+
@UnavailableWrapper var unavailableInferred = S() // expected-error {{'UnavailableWrapper' is unavailable}}
100+
101+
@WrappedValueUnavailableOnMacOS var unavailableWrappedValue: S
102+
@WrappedValueAvailable51 var wrappedValueAavailable51: S // expected-error {{'wrappedValue' is only available in macOS 51 or newer}}
103+
}
104+
105+
func alwaysAvailableFunc( // expected-note 2 {{add @available attribute to enclosing global function}}
61106
@AlwaysAvailableWrapper _ alwaysAvailable: S,
62107
@Available51Wrapper _ available51: S, // expected-error {{'Available51Wrapper' is only available in macOS 51 or newer}}
63-
@UnavailableWrapper _ unavailable: S // expected-error {{'UnavailableWrapper' is unavailable}}
108+
@UnavailableWrapper _ unavailable: S, // expected-error {{'UnavailableWrapper' is unavailable}}
109+
@WrappedValueUnavailableOnMacOS _ unavailableWrappedValue: S, // expected-error {{'wrappedValue' is unavailable in macOS}}
110+
@WrappedValueAvailable51 _ wrappedValueAavailable51: S // expected-error {{'wrappedValue' is only available in macOS 51 or newer}}
64111
) {}
65112

66113
@available(macOS 51, *)
67114
func available51Func(
68115
@AlwaysAvailableWrapper _ alwaysAvailable: S,
69116
@Available51Wrapper _ available51: S,
70-
@UnavailableWrapper _ unavailable: S // expected-error {{'UnavailableWrapper' is unavailable}}
117+
@UnavailableWrapper _ unavailable: S, // expected-error {{'UnavailableWrapper' is unavailable}}
118+
@WrappedValueUnavailableOnMacOS _ unavailableWrappedValue: S, // expected-error {{'wrappedValue' is unavailable in macOS}}
119+
@WrappedValueAvailable51 _ wrappedValueAavailable51: S
71120
) {}
72121

73122
@available(*, unavailable)
74123
func unavailableFunc(
75124
@AlwaysAvailableWrapper _ alwaysAvailable: S,
76125
@Available51Wrapper _ available51: S,
77-
@UnavailableWrapper _ unavailable: S
126+
@UnavailableWrapper _ unavailable: S,
127+
@WrappedValueUnavailableOnMacOS _ unavailableWrappedValue: S, // expected-error {{'wrappedValue' is unavailable in macOS}}
128+
@WrappedValueAvailable51 _ wrappedValueAavailable51: S // expected-error {{'wrappedValue' is only available in macOS 51 or newer}}
129+
) {}
130+
131+
@available(macOS, unavailable)
132+
func unavailableOnMacOSFunc(
133+
@AlwaysAvailableWrapper _ alwaysAvailable: S,
134+
@Available51Wrapper _ available51: S,
135+
@UnavailableWrapper _ unavailable: S,
136+
@WrappedValueUnavailableOnMacOS _ unavailableWrappedValue: S,
137+
@WrappedValueAvailable51 _ wrappedValueAavailable51: S // expected-error {{'wrappedValue' is only available in macOS 51 or newer}}
78138
) {}

test/Sema/property_wrapper_parameter_invalid.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ struct Wrapper<T> { // expected-note 3 {{type declared here}}
7777
self.wrappedValue = projectedValue.value
7878
}
7979

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

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

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

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

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

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

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

224+
// expected-error@+3 {{property 'wrappedValue' is package and cannot be referenced from an '@inlinable' function}}
217225
// expected-error@+2 {{generic struct 'PackageWrapper' is package and cannot be referenced from an '@inlinable' function}}
218226
// expected-error@+1 {{initializer 'init(wrappedValue:)' is package and cannot be referenced from an '@inlinable' function}}
219227
@inlinable func testComposition6pkg(@PackageWrapper @PublicWrapper value: Int) {}

test/decl/var/property_wrappers.swift

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -961,7 +961,7 @@ struct Observable<Value> {
961961
}
962962

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

988+
func takesObservable(@Observable _ observable: Int) {} // expected-error{{'wrappedValue' is unavailable: must be in a class}}
989+
990+
class MyObservedClass {
991+
@Observable
992+
var observedProperty = 17
993+
}
994+
988995
// ---------------------------------------------------------------------------
989996
// Miscellaneous bugs
990997
// ---------------------------------------------------------------------------

0 commit comments

Comments
 (0)