Skip to content

Commit 70a7d85

Browse files
authored
Merge pull request #41112 from tshortli/diagnose-available-wrapped-properties
[Sema] Diagnose @available attribute on wrapped and lazy properties
2 parents 0e6d10b + e34196d commit 70a7d85

File tree

8 files changed

+58
-32
lines changed

8 files changed

+58
-32
lines changed

include/swift/AST/Decl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5396,6 +5396,10 @@ class VarDecl : public AbstractStorageDecl {
53965396
/// an attached property wrapper.
53975397
VarDecl *getPropertyWrapperWrappedValueVar() const;
53985398

5399+
/// Return true if this property either has storage or has an attached property
5400+
/// wrapper that has storage.
5401+
bool hasStorageOrWrapsStorage() const;
5402+
53995403
/// Visit all auxiliary declarations to this VarDecl.
54005404
///
54015405
/// An auxiliary declaration is a declaration synthesized by the compiler to support

lib/AST/Decl.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6524,6 +6524,20 @@ VarDecl *VarDecl::getPropertyWrapperWrappedValueVar() const {
65246524
return getPropertyWrapperAuxiliaryVariables().localWrappedValueVar;
65256525
}
65266526

6527+
bool VarDecl::hasStorageOrWrapsStorage() const {
6528+
if (hasStorage())
6529+
return true;
6530+
6531+
if (getAttrs().hasAttribute<LazyAttr>())
6532+
return true;
6533+
6534+
auto *backing = getPropertyWrapperBackingProperty();
6535+
if (backing && backing->hasStorage())
6536+
return true;
6537+
6538+
return false;
6539+
}
6540+
65276541
void VarDecl::visitAuxiliaryDecls(llvm::function_ref<void(VarDecl *)> visit) const {
65286542
if (getDeclContext()->isTypeContext() || isImplicit())
65296543
return;

lib/Sema/CodeSynthesis.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -928,10 +928,7 @@ bool AreAllStoredPropertiesDefaultInitableRequest::evaluate(
928928
if (VD->getAttrs().hasAttribute<NSManagedAttr>())
929929
CheckDefaultInitializer = false;
930930

931-
if (VD->hasStorage())
932-
HasStorage = true;
933-
auto *backing = VD->getPropertyWrapperBackingProperty();
934-
if (backing && backing->hasStorage())
931+
if (VD->hasStorageOrWrapsStorage())
935932
HasStorage = true;
936933
});
937934

lib/Sema/TypeCheckAttr.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3562,7 +3562,7 @@ TypeChecker::diagnosticIfDeclCannotBePotentiallyUnavailable(const Decl *D) {
35623562
auto *DC = D->getDeclContext();
35633563

35643564
if (auto *VD = dyn_cast<VarDecl>(D)) {
3565-
if (!VD->hasStorage())
3565+
if (!VD->hasStorageOrWrapsStorage())
35663566
return None;
35673567

35683568
// Do not permit potential availability of script-mode global variables;

test/Sema/availability_stored.swift

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,29 +8,55 @@
88
@available(macOS 50, *)
99
struct NewStruct {}
1010

11+
@available(macOS 50, *)
12+
@propertyWrapper
13+
struct NewPropertyWrapper<Value> {
14+
var wrappedValue: Value
15+
}
16+
1117
@available(macOS 50, *)
1218
struct GoodReferenceStruct {
1319
var x: NewStruct
20+
@NewPropertyWrapper var y: Int
21+
lazy var z: Int = 42
1422
}
1523

1624
@available(macOS 50, *)
1725
struct GoodNestedReferenceStruct {
1826
struct Inner {
1927
var x: NewStruct
28+
@NewPropertyWrapper var y: Int
29+
lazy var z: Int = 42
2030
}
2131
}
2232

2333
struct BadReferenceStruct1 {
2434
// expected-error@+1 {{stored properties cannot be marked potentially unavailable with '@available'}}
2535
@available(macOS 50, *)
2636
var x: NewStruct
37+
38+
// expected-error@+1 {{stored properties cannot be marked potentially unavailable with '@available'}}
39+
@available(macOS 50, *)
40+
@NewPropertyWrapper var y: Int
41+
42+
// expected-error@+1 {{stored properties cannot be marked potentially unavailable with '@available'}}
43+
@available(macOS 50, *)
44+
lazy var z: Int = 42
2745
}
2846

2947
@available(macOS 40, *)
3048
struct BadReferenceStruct2 {
3149
// expected-error@+1 {{stored properties cannot be marked potentially unavailable with '@available'}}
3250
@available(macOS 50, *)
3351
var x: NewStruct
52+
53+
// expected-error@+1 {{stored properties cannot be marked potentially unavailable with '@available'}}
54+
@available(macOS 50, *)
55+
@NewPropertyWrapper var y: Int
56+
57+
// expected-error@+1 {{stored properties cannot be marked potentially unavailable with '@available'}}
58+
@available(macOS 50, *)
59+
lazy var z: Int = 42
3460
}
3561

3662
// The same behavior should hold for enum elements with payloads.

test/Sema/availability_versions.swift

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,7 @@ class ClassWithUnavailableProperties {
324324
@available(OSX, introduced: 10.9)
325325
lazy var availableOn10_9Stored: Int = 9
326326

327-
@available(OSX, introduced: 10.51)
327+
@available(OSX, introduced: 10.51) // expected-error {{stored properties cannot be marked potentially unavailable with '@available'}}
328328
lazy var availableOn10_51Stored : Int = 10
329329

330330
@available(OSX, introduced: 10.9)
@@ -418,7 +418,6 @@ class ClassWithReferencesInInitializers {
418418
lazy var lazyPropWithInitializer10_51: Int = globalFuncAvailableOn10_51()
419419

420420
lazy var lazyPropWithInitializer10_52: Int = globalFuncAvailableOn10_52() // expected-error {{'globalFuncAvailableOn10_52()' is only available in macOS 10.52 or newer}}
421-
// expected-note@-1 {{add @available attribute to enclosing property}}
422421
}
423422

424423
func accessUnavailableProperties(_ o: ClassWithUnavailableProperties) {
@@ -716,21 +715,9 @@ class ClassWithDeclarationsOfUnavailableClasses {
716715
// expected-note@-1 5{{add @available attribute to enclosing class}}
717716

718717
@available(OSX, introduced: 10.51)
719-
init() {
720-
unavailablePropertyOfUnavailableType = ClassAvailableOn10_51()
721-
unavailablePropertyOfUnavailableType = ClassAvailableOn10_51()
722-
}
718+
init() {}
723719

724720
var propertyOfUnavailableType: ClassAvailableOn10_51 // expected-error {{'ClassAvailableOn10_51' is only available in macOS 10.51 or newer}}
725-
726-
@available(OSX, introduced: 10.51)
727-
lazy var unavailablePropertyOfUnavailableType: ClassAvailableOn10_51 = ClassAvailableOn10_51()
728-
729-
@available(OSX, introduced: 10.51)
730-
lazy var unavailablePropertyOfOptionalUnavailableType: ClassAvailableOn10_51? = nil
731-
732-
@available(OSX, introduced: 10.51)
733-
lazy var unavailablePropertyOfUnavailableTypeWithInitializer: ClassAvailableOn10_51 = ClassAvailableOn10_51()
734721

735722
@available(OSX, introduced: 10.51)
736723
static var unavailableStaticPropertyOfUnavailableType: ClassAvailableOn10_51 = ClassAvailableOn10_51()
@@ -1294,15 +1281,12 @@ class ClassForFixit {
12941281

12951282
lazy var fixitForReferenceInLazyPropertyType: ClassAvailableOn10_51? = nil
12961283
// expected-error@-1 {{'ClassAvailableOn10_51' is only available in macOS 10.51 or newer}}
1297-
// expected-note@-2 {{add @available attribute to enclosing property}} {{3-3=@available(macOS 10.51, *)\n }}
12981284

12991285
private lazy var fixitForReferenceInPrivateLazyPropertyType: ClassAvailableOn10_51? = nil
13001286
// expected-error@-1 {{'ClassAvailableOn10_51' is only available in macOS 10.51 or newer}}
1301-
// expected-note@-2 {{add @available attribute to enclosing property}} {{3-3=@available(macOS 10.51, *)\n }}
13021287

13031288
lazy private var fixitForReferenceInLazyPrivatePropertyType: ClassAvailableOn10_51? = nil
13041289
// expected-error@-1 {{'ClassAvailableOn10_51' is only available in macOS 10.51 or newer}}
1305-
// expected-note@-2 {{add @available attribute to enclosing property}} {{3-3=@available(macOS 10.51, *)\n }}
13061290

13071291
static var fixitForReferenceInStaticPropertyType: ClassAvailableOn10_51? = nil
13081292
// expected-error@-1 {{'ClassAvailableOn10_51' is only available in macOS 10.51 or newer}}

test/decl/class/effectful_properties.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ class AcceptableDynamic {
8686
}
8787

8888
// mainly just some sanity checks
89+
// expected-error@+1 {{class 'Misc' has no initializers}}
8990
class Misc {
9091
// expected-error@+2 {{'lazy' cannot be used on a computed property}}
9192
// expected-error@+1 {{lazy properties must have an initializer}}

test/stdlib/CodableTests.swift

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,7 @@ class TestCodable : TestCodableSuper {
434434

435435
// MARK: - DateInterval
436436
@available(macOS 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)
437-
lazy var dateIntervalValues: [Int : DateInterval] = [
437+
static let dateIntervalValues: [Int : DateInterval] = [
438438
#line : DateInterval(),
439439
#line : DateInterval(start: Date.distantPast, end: Date()),
440440
#line : DateInterval(start: Date(), end: Date.distantFuture),
@@ -443,14 +443,14 @@ class TestCodable : TestCodableSuper {
443443

444444
@available(macOS 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)
445445
func test_DateInterval_JSON() {
446-
for (testLine, interval) in dateIntervalValues {
446+
for (testLine, interval) in Self.dateIntervalValues {
447447
expectRoundTripEqualityThroughJSON(for: interval, lineNumber: testLine)
448448
}
449449
}
450450

451451
@available(macOS 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)
452452
func test_DateInterval_Plist() {
453-
for (testLine, interval) in dateIntervalValues {
453+
for (testLine, interval) in Self.dateIntervalValues {
454454
expectRoundTripEqualityThroughPlist(for: interval, lineNumber: testLine)
455455
}
456456
}
@@ -641,15 +641,15 @@ class TestCodable : TestCodableSuper {
641641

642642
// MARK: - Measurement
643643
@available(macOS 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)
644-
lazy var unitValues: [Int : Dimension] = [
644+
static let unitValues: [Int : Dimension] = [
645645
#line : UnitAcceleration.metersPerSecondSquared,
646646
#line : UnitMass.kilograms,
647647
#line : UnitLength.miles
648648
]
649649

650650
@available(macOS 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)
651651
func test_Measurement_JSON() {
652-
for (testLine, unit) in unitValues {
652+
for (testLine, unit) in Self.unitValues {
653653
// FIXME: <rdar://problem/49026133>
654654
// Terminating due to uncaught exception NSInvalidArgumentException:
655655
// *** You must override baseUnit in your class NSDimension to define its base unit.
@@ -660,7 +660,7 @@ class TestCodable : TestCodableSuper {
660660

661661
@available(macOS 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)
662662
func test_Measurement_Plist() {
663-
for (testLine, unit) in unitValues {
663+
for (testLine, unit) in Self.unitValues {
664664
// FIXME: <rdar://problem/49026133>
665665
// Terminating due to uncaught exception NSInvalidArgumentException:
666666
// *** You must override baseUnit in your class NSDimension to define its base unit.
@@ -741,22 +741,22 @@ class TestCodable : TestCodableSuper {
741741

742742
// MARK: - PersonNameComponents
743743
@available(macOS 10.11, iOS 9.0, watchOS 2.0, tvOS 9.0, *)
744-
lazy var personNameComponentsValues: [Int : PersonNameComponents] = [
744+
static let personNameComponentsValues: [Int : PersonNameComponents] = [
745745
#line : makePersonNameComponents(givenName: "John", familyName: "Appleseed"),
746746
#line : makePersonNameComponents(givenName: "John", familyName: "Appleseed", nickname: "Johnny"),
747747
#line : makePersonNameComponents(namePrefix: "Dr.", givenName: "Jane", middleName: "A.", familyName: "Appleseed", nameSuffix: "Esq.", nickname: "Janie")
748748
]
749749

750750
@available(macOS 10.11, iOS 9.0, watchOS 2.0, tvOS 9.0, *)
751751
func test_PersonNameComponents_JSON() {
752-
for (testLine, components) in personNameComponentsValues {
752+
for (testLine, components) in Self.personNameComponentsValues {
753753
expectRoundTripEqualityThroughJSON(for: components, lineNumber: testLine)
754754
}
755755
}
756756

757757
@available(macOS 10.11, iOS 9.0, watchOS 2.0, tvOS 9.0, *)
758758
func test_PersonNameComponents_Plist() {
759-
for (testLine, components) in personNameComponentsValues {
759+
for (testLine, components) in Self.personNameComponentsValues {
760760
expectRoundTripEqualityThroughPlist(for: components, lineNumber: testLine)
761761
}
762762
}

0 commit comments

Comments
 (0)