Skip to content

Commit 34f4e39

Browse files
authored
Merge pull request #64310 from tshortli/availability-inference
AST: Improve accuracy of inferred availability for synthesized declarations
2 parents ab3a8c3 + 4058ad1 commit 34f4e39

File tree

4 files changed

+160
-24
lines changed

4 files changed

+160
-24
lines changed

lib/AST/Availability.cpp

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -143,26 +143,54 @@ void AvailabilityInference::applyInferredAvailableAttrs(
143143
// a per-platform basis.
144144
std::map<PlatformKind, InferredAvailability> Inferred;
145145
for (const Decl *D : InferredFromDecls) {
146-
for (const DeclAttribute *Attr : D->getAttrs()) {
147-
auto *AvAttr = dyn_cast<AvailableAttr>(Attr);
148-
if (!AvAttr || AvAttr->isInvalid())
149-
continue;
146+
do {
147+
for (const DeclAttribute *Attr : D->getAttrs()) {
148+
auto *AvAttr = dyn_cast<AvailableAttr>(Attr);
149+
if (!AvAttr || AvAttr->isInvalid())
150+
continue;
150151

151-
mergeWithInferredAvailability(AvAttr, Inferred[AvAttr->Platform]);
152+
mergeWithInferredAvailability(AvAttr, Inferred[AvAttr->Platform]);
152153

153-
if (Message.empty() && !AvAttr->Message.empty())
154-
Message = AvAttr->Message;
154+
if (Message.empty() && !AvAttr->Message.empty())
155+
Message = AvAttr->Message;
155156

156-
if (Rename.empty() && !AvAttr->Rename.empty()) {
157-
Rename = AvAttr->Rename;
158-
RenameDecl = AvAttr->RenameDecl;
157+
if (Rename.empty() && !AvAttr->Rename.empty()) {
158+
Rename = AvAttr->Rename;
159+
RenameDecl = AvAttr->RenameDecl;
160+
}
159161
}
162+
163+
// Walk up the enclosing declaration hierarchy to make sure we aren't
164+
// missing any inherited attributes.
165+
D = AvailabilityInference::parentDeclForInferredAvailability(D);
166+
} while (D);
167+
}
168+
169+
DeclAttributes &Attrs = ToDecl->getAttrs();
170+
171+
// Some kinds of platform agnostic availability supersede any platform
172+
// specific availability.
173+
auto InferredAgnostic = Inferred.find(PlatformKind::none);
174+
if (InferredAgnostic != Inferred.end()) {
175+
switch (InferredAgnostic->second.PlatformAgnostic) {
176+
case PlatformAgnosticAvailabilityKind::Deprecated:
177+
case PlatformAgnosticAvailabilityKind::UnavailableInSwift:
178+
case PlatformAgnosticAvailabilityKind::Unavailable:
179+
Attrs.add(createAvailableAttr(PlatformKind::none,
180+
InferredAgnostic->second, Message, Rename,
181+
RenameDecl, Context));
182+
return;
183+
184+
case PlatformAgnosticAvailabilityKind::None:
185+
case PlatformAgnosticAvailabilityKind::SwiftVersionSpecific:
186+
case PlatformAgnosticAvailabilityKind::PackageDescriptionVersionSpecific:
187+
case PlatformAgnosticAvailabilityKind::NoAsync:
188+
break;
160189
}
161190
}
162191

163192
// Create an availability attribute for each observed platform and add
164193
// to ToDecl.
165-
DeclAttributes &Attrs = ToDecl->getAttrs();
166194
for (auto &Pair : Inferred) {
167195
auto *Attr = createAvailableAttr(Pair.first, Pair.second, Message,
168196
Rename, RenameDecl, Context);

test/ModuleInterface/actor_availability.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,4 +65,16 @@ extension Enum {
6565
// CHECK-NEXT: get
6666
// CHECK-NEXT: }
6767
}
68+
69+
// CHECK: #if compiler(>=5.3) && $Actors
70+
// CHECK-NEXT: @_hasMissingDesignatedInitializers @available(macOS, unavailable)
71+
// CHECK-NEXT: public actor UnavailableExtensionNestedActor {
72+
@available(macOS, unavailable)
73+
public actor UnavailableExtensionNestedActor {
74+
// CHECK: @available(iOS 13.4, tvOS 13.4, watchOS 6.2, *)
75+
// CHECK-NEXT: @available(macOS, unavailable)
76+
// CHECK-NEXT: @_semantics("defaultActor") nonisolated final public var unownedExecutor: _Concurrency.UnownedSerialExecutor {
77+
// CHECK-NEXT: get
78+
// CHECK-NEXT: }
79+
}
6880
}

test/Sema/generalized_accessors_availability.swift

Lines changed: 76 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// RUN: %empty-directory(%t)
2-
// RUN: %target-swift-frontend -target %target-cpu-apple-macosx10.9 -typecheck -verify %s
2+
// RUN: %target-swift-frontend -target %target-cpu-apple-macosx10.50 -typecheck -verify %s
33

44
// REQUIRES: OS=macosx
55

@@ -8,14 +8,14 @@ struct SetterConditionallyAvailable<T> {
88
var wrappedValue: T {
99
get { fatalError() }
1010

11-
@available(macOS 10.10, *)
11+
@available(macOS 10.51, *)
1212
set { fatalError() }
1313
}
1414

1515
var projectedValue: T {
1616
get { fatalError() }
1717

18-
@available(macOS 10.10, *)
18+
@available(macOS 10.51, *)
1919
set { fatalError() }
2020
}
2121
}
@@ -25,14 +25,48 @@ struct ModifyConditionallyAvailable<T> {
2525
var wrappedValue: T {
2626
get { fatalError() }
2727

28-
@available(macOS 10.10, *)
28+
@available(macOS 10.51, *)
2929
_modify { fatalError() }
3030
}
3131

3232
var projectedValue: T {
3333
get { fatalError() }
3434

35-
@available(macOS 10.10, *)
35+
@available(macOS 10.51, *)
36+
_modify { fatalError() }
37+
}
38+
}
39+
40+
@propertyWrapper
41+
struct SetterMoreAvailable<T> {
42+
var wrappedValue: T {
43+
get { fatalError() }
44+
45+
@available(macOS 10.49, *)
46+
set { fatalError() }
47+
}
48+
49+
var projectedValue: T {
50+
get { fatalError() }
51+
52+
@available(macOS 10.49, *)
53+
set { fatalError() }
54+
}
55+
}
56+
57+
@propertyWrapper
58+
struct ModifyMoreAvailable<T> {
59+
var wrappedValue: T {
60+
get { fatalError() }
61+
62+
@available(macOS 10.49, *)
63+
_modify { fatalError() }
64+
}
65+
66+
var projectedValue: T {
67+
get { fatalError() }
68+
69+
@available(macOS 10.49, *)
3670
_modify { fatalError() }
3771
}
3872
}
@@ -41,7 +75,7 @@ struct Butt {
4175
var modify_conditionally_available: Int {
4276
get { fatalError() }
4377

44-
@available(macOS 10.10, *)
78+
@available(macOS 10.51, *)
4579
_modify { fatalError() }
4680
}
4781

@@ -50,16 +84,26 @@ struct Butt {
5084

5185
@ModifyConditionallyAvailable
5286
var wrapped_modify_conditionally_available: Int
87+
88+
@SetterMoreAvailable
89+
var wrapped_setter_more_available: Int
90+
91+
@ModifyMoreAvailable
92+
var wrapped_modify_more_available: Int
5393
}
5494

55-
func butt(x: inout Butt) { // expected-note*{{}}
56-
x.modify_conditionally_available = 0 // expected-error{{only available in macOS 10.10 or newer}} expected-note{{}}
57-
x.wrapped_setter_conditionally_available = 0 // expected-error{{only available in macOS 10.10 or newer}} expected-note{{}}
58-
x.wrapped_modify_conditionally_available = 0 // expected-error{{only available in macOS 10.10 or newer}} expected-note{{}}
59-
x.$wrapped_setter_conditionally_available = 0 // expected-error{{only available in macOS 10.10 or newer}} expected-note{{}}
60-
x.$wrapped_modify_conditionally_available = 0 // expected-error{{only available in macOS 10.10 or newer}} expected-note{{}}
95+
func butt(x: inout Butt) { // expected-note * {{}}
96+
x.modify_conditionally_available = 0 // expected-error {{only available in macOS 10.51 or newer}} expected-note{{}}
97+
x.wrapped_setter_conditionally_available = 0 // expected-error {{only available in macOS 10.51 or newer}} expected-note{{}}
98+
x.wrapped_modify_conditionally_available = 0 // expected-error {{only available in macOS 10.51 or newer}} expected-note{{}}
99+
x.$wrapped_setter_conditionally_available = 0 // expected-error {{only available in macOS 10.51 or newer}} expected-note{{}}
100+
x.$wrapped_modify_conditionally_available = 0 // expected-error {{only available in macOS 10.51 or newer}} expected-note{{}}
101+
x.wrapped_setter_more_available = 0
102+
x.wrapped_modify_more_available = 0
103+
x.$wrapped_setter_more_available = 0
104+
x.$wrapped_modify_more_available = 0
61105

62-
if #available(macOS 10.10, *) {
106+
if #available(macOS 10.51, *) {
63107
x.modify_conditionally_available = 0
64108
x.wrapped_setter_conditionally_available = 0
65109
x.wrapped_modify_conditionally_available = 0
@@ -68,6 +112,25 @@ func butt(x: inout Butt) { // expected-note*{{}}
68112
}
69113
}
70114

115+
@available(macOS, unavailable)
116+
extension Butt {
117+
@available(iOS, unavailable)
118+
struct Nested { // expected-note {{has been explicitly marked unavailable here}}
119+
@SetterMoreAvailable
120+
var wrapped_setter_more_available: Int // expected-note 2 {{has been explicitly marked unavailable here}}
121+
122+
@ModifyMoreAvailable
123+
var wrapped_modify_more_available: Int // expected-note 2 {{has been explicitly marked unavailable here}}
124+
}
125+
}
126+
127+
func testButtNested(x: inout Butt.Nested) { // expected-error {{'Nested' is unavailable in macOS}}
128+
x.wrapped_setter_more_available = 0 // expected-error {{is unavailable in macOS}}
129+
x.wrapped_modify_more_available = 0 // expected-error {{is unavailable in macOS}}
130+
x.$wrapped_setter_more_available = 0 // expected-error {{is unavailable in macOS}}
131+
x.$wrapped_modify_more_available = 0 // expected-error {{is unavailable in macOS}}
132+
}
133+
71134
@available(macOS 11.0, *)
72135
struct LessAvailable {
73136
@SetterConditionallyAvailable
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// RUN: %target-typecheck-verify-swift -target %target-cpu-apple-macosx12 -swift-version 5
2+
3+
// REQUIRES: objc_interop
4+
// REQUIRES: OS=macosx
5+
6+
import SwiftUI
7+
8+
@available(macOS 12, *)
9+
struct S {}
10+
11+
@available(iOS, unavailable)
12+
extension S {
13+
class NestedOtherPlatformUnavailable {
14+
@Published var x: Int = 0
15+
@Binding var y: Bool
16+
17+
init(y: Binding<Bool>) {
18+
_y = y
19+
}
20+
}
21+
}
22+
23+
@available(*, unavailable)
24+
extension S {
25+
class NestedAlwaysUnavailable {
26+
@Published var x: Int = 0
27+
@Binding var y: Bool
28+
29+
init(y: Binding<Bool>) {
30+
_y = y
31+
}
32+
}
33+
}

0 commit comments

Comments
 (0)