Skip to content

Commit d82153b

Browse files
committed
AST: Emit correct synthesized availability attributes for unownedExecutor property.
When synthesizing a declaration and inferring its availability, the synthesized attribute should factor in unavailability of the parent declarations. This recently regressed with #63361. However, the previous implementation did not produce correct results, either, because the logic for merging availability attributes produced a non-sensical result when both `unavailable` and `introduced:` availability attributes were merged. For example, this was the result for the synthesized `unownedExecutor` property of an actor when the actor was marked unavailable: ``` @available(macOS, unavailable) actor A { // Incorrectly synthesized availability for `unownedExecutor` which results from merging // the unavailability of the parent and the availability of the UnownedSerialExecutor type. @available(macOS, unavailable, introduced: macOS 10.15) @_semantics("defaultActor") nonisolated final var unownedExecutor: UnownedSerialExecutor { get } } ``` This is fixed by omitting all version components from the synthesized attribute when the overall attribute kind is "unavailable". Additionally, I discovered that the `concurrency_availability.swift` test case was no longer testing what it intended to test. The conformances to `Actor` for each `actor` in the test were no longer being synthesized and therefore `unownedExecutor` was not being synthesized. That was fixed by importing the `_Concurrency` module directly, which seems to be necessary because of the `-parse-stdlib` flag in the test. Resolves rdar://106055566
1 parent d375601 commit d82153b

File tree

5 files changed

+122
-11
lines changed

5 files changed

+122
-11
lines changed

include/swift/AST/Availability.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,10 @@ class AvailabilityContext {
334334

335335
class AvailabilityInference {
336336
public:
337+
/// Returns the decl that should be considered the parent decl of the given
338+
/// decl when looking for inherited availability annotations.
339+
static const Decl *parentDeclForInferredAvailability(const Decl *D);
340+
337341
/// Infers the common availability required to access an array of
338342
/// declarations and adds attributes reflecting that availability
339343
/// to ToDecl.

lib/AST/Availability.cpp

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,14 +102,22 @@ static AvailableAttr *createAvailableAttr(PlatformKind Platform,
102102
StringRef Rename,
103103
ValueDecl *RenameDecl,
104104
ASTContext &Context) {
105-
106105
llvm::VersionTuple Introduced =
107106
Inferred.Introduced.value_or(llvm::VersionTuple());
108107
llvm::VersionTuple Deprecated =
109108
Inferred.Deprecated.value_or(llvm::VersionTuple());
110109
llvm::VersionTuple Obsoleted =
111110
Inferred.Obsoleted.value_or(llvm::VersionTuple());
112111

112+
// If a decl is unavailable then it cannot have any introduced, deprecated, or
113+
// obsoleted version.
114+
if (Inferred.PlatformAgnostic ==
115+
PlatformAgnosticAvailabilityKind::Unavailable) {
116+
Introduced = llvm::VersionTuple();
117+
Deprecated = llvm::VersionTuple();
118+
Obsoleted = llvm::VersionTuple();
119+
}
120+
113121
return new (Context)
114122
AvailableAttr(SourceLoc(), SourceRange(), Platform,
115123
Message, Rename, RenameDecl,
@@ -165,7 +173,8 @@ void AvailabilityInference::applyInferredAvailableAttrs(
165173

166174
/// Returns the decl that should be considered the parent decl of the given decl
167175
/// when looking for inherited availability annotations.
168-
static Decl *parentDeclForAvailability(const Decl *D) {
176+
const Decl *
177+
AvailabilityInference::parentDeclForInferredAvailability(const Decl *D) {
169178
if (auto *AD = dyn_cast<AccessorDecl>(D))
170179
return AD->getStorage();
171180

@@ -230,7 +239,8 @@ SemanticAvailableRangeAttrRequest::evaluate(Evaluator &evaluator,
230239
decl, decl->getASTContext()))
231240
return std::make_pair(attr, decl);
232241

233-
if (auto *parent = parentDeclForAvailability(decl))
242+
if (auto *parent =
243+
AvailabilityInference::parentDeclForInferredAvailability(decl))
234244
return parent->getSemanticAvailableRangeAttr();
235245

236246
return None;
@@ -262,7 +272,8 @@ SemanticUnavailableAttrRequest::evaluate(Evaluator &evaluator,
262272
if (auto attr = decl->getAttrs().getUnavailable(decl->getASTContext()))
263273
return std::make_pair(attr, decl);
264274

265-
if (auto *parent = parentDeclForAvailability(decl))
275+
if (auto *parent =
276+
AvailabilityInference::parentDeclForInferredAvailability(decl))
266277
return parent->getSemanticUnavailableAttr();
267278

268279
return None;

lib/AST/Decl.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -477,8 +477,12 @@ unsigned Decl::getAttachedMacroDiscriminator(
477477
}
478478

479479
const Decl *Decl::getInnermostDeclWithAvailability() const {
480-
if (auto attrAndDecl = getSemanticAvailableRangeAttr())
481-
return attrAndDecl.value().second;
480+
if (getAttrs().hasAttribute<AvailableAttr>())
481+
return this;
482+
483+
if (auto parent =
484+
AvailabilityInference::parentDeclForInferredAvailability(this))
485+
return parent->getInnermostDeclWithAvailability();
482486

483487
return nullptr;
484488
}

test/Concurrency/concurrency_availability.swift

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
// RUN: %target-swift-frontend -parse-stdlib -target x86_64-apple-macosx12 -typecheck %s -DTARGET_MACOS_12
44
// REQUIRES: OS=macosx
55

6+
import _Concurrency
7+
68
func f() async { } // expected-error{{concurrency is only available in}}
79
// expected-note@-1{{add @available}}
810

@@ -13,19 +15,41 @@ actor A { } // expected-error{{concurrency is only available in}}
1315
public func swift_deletedAsyncMethodError() async {
1416
}
1517

16-
// Ensure that our synthesis of the actor's unownedExecutor does not cause
17-
// availability errors.
1818
@available(macOS 12.0, *)
1919
struct S {
20-
actor A {
20+
// Ensure that our synthesis of the actor's unownedExecutor does not cause
21+
// availability errors.
22+
actor NestedActor {
23+
}
24+
25+
// The synthesized unownedExecutor inside this actor should inherit the
26+
// un-availability of UnavailableActor.
27+
@available(macOS, unavailable)
28+
actor UnavailableActor {
2129
}
2230
}
2331

32+
#if TARGET_MACOS_12
2433
// The synthesized unownedExecutor inside this extension on S should inherit
2534
// availability from S to avoid availability errors.
26-
#if TARGET_MACOS_12
2735
extension S {
28-
actor A2 {
36+
actor ExtensionNestedActor {
2937
}
3038
}
3139
#endif
40+
41+
// Make sure that the conformances to Actor are actually being synthesized
42+
// since otherwise this test isn't actually testing what it is designed to test.
43+
@available(macOS 10.15, *)
44+
func takesExecutor(_ e: UnownedSerialExecutor) { }
45+
46+
@available(macOS 12.0, *)
47+
func testNestedActorConformance(_ a: S.NestedActor) {
48+
takesExecutor(a.unownedExecutor)
49+
}
50+
51+
#if TARGET_MACOS_12
52+
func testExtensionNestedActorConformance(_ a: S.ExtensionNestedActor) {
53+
takesExecutor(a.unownedExecutor)
54+
}
55+
#endif
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-emit-module-interface(%t/Library.swiftinterface) %s -module-name Library -target %target-swift-abi-5.3-triple
3+
// RUN: %target-swift-typecheck-module-from-interface(%t/Library.swiftinterface) -module-name Library
4+
// RUN: %FileCheck %s < %t/Library.swiftinterface
5+
6+
// REQUIRES: VENDOR=apple
7+
8+
// CHECK: #if compiler(>=5.3) && $Actors
9+
// CHECK-NEXT: public actor ActorWithImplicitAvailability {
10+
public actor ActorWithImplicitAvailability {
11+
// CHECK: @available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *)
12+
// CHECK-NEXT: @_semantics("defaultActor") nonisolated final public var unownedExecutor: _Concurrency.UnownedSerialExecutor {
13+
// CHECK-NEXT: get
14+
// CHECK-NEXT: }
15+
}
16+
// CHECK: #endif
17+
18+
// CHECK: #if compiler(>=5.3) && $Actors
19+
// CHECK-NEXT: @available(macOS 10.15.4, iOS 13.4, watchOS 6.2, tvOS 13.4, *)
20+
// CHECK-NEXT: public actor ActorWithExplicitAvailability {
21+
@available(SwiftStdlib 5.2, *)
22+
public actor ActorWithExplicitAvailability {
23+
// CHECK: @available(iOS 13.4, tvOS 13.4, watchOS 6.2, macOS 10.15.4, *)
24+
// CHECK-NEXT: @_semantics("defaultActor") nonisolated final public var unownedExecutor: _Concurrency.UnownedSerialExecutor {
25+
// CHECK-NEXT: get
26+
// CHECK-NEXT: }
27+
}
28+
// CHECK: #endif
29+
30+
// CHECK: #if compiler(>=5.3) && $Actors
31+
// CHECK-NEXT: @_hasMissingDesignatedInitializers @available(macOS, unavailable)
32+
// CHECK-NEXT: public actor UnavailableActor {
33+
@available(macOS, unavailable)
34+
public actor UnavailableActor {
35+
// CHECK: @available(iOS 13.0, tvOS 13.0, watchOS 6.0, *)
36+
// CHECK-NEXT: @available(macOS, unavailable)
37+
// CHECK-NEXT: @_semantics("defaultActor") nonisolated final public var unownedExecutor: _Concurrency.UnownedSerialExecutor {
38+
// CHECK-NEXT: get
39+
// CHECK-NEXT: }
40+
}
41+
// CHECK: #endif
42+
43+
// CHECK: @available(macOS 10.15.4, iOS 13.4, watchOS 6.2, tvOS 13.4, *)
44+
// CHECK-NEXT: public enum Enum {
45+
@available(SwiftStdlib 5.2, *)
46+
public enum Enum {
47+
// CHECK: #if compiler(>=5.3) && $Actors
48+
// CHECK-NEXT: @_hasMissingDesignatedInitializers public actor NestedActor {
49+
public actor NestedActor {
50+
// CHECK: @available(iOS 13.4, tvOS 13.4, watchOS 6.2, macOS 10.15.4, *)
51+
// CHECK-NEXT: @_semantics("defaultActor") nonisolated final public var unownedExecutor: _Concurrency.UnownedSerialExecutor {
52+
// CHECK-NEXT: get
53+
// CHECK-NEXT: }
54+
}
55+
// CHECK: #endif
56+
}
57+
58+
// CHECK: extension Library.Enum {
59+
extension Enum {
60+
// CHECK: #if compiler(>=5.3) && $Actors
61+
// CHECK-NEXT: @_hasMissingDesignatedInitializers public actor ExtensionNestedActor {
62+
public actor ExtensionNestedActor {
63+
// CHECK: @available(iOS 13.4, tvOS 13.4, watchOS 6.2, macOS 10.15.4, *)
64+
// CHECK-NEXT: @_semantics("defaultActor") nonisolated final public var unownedExecutor: _Concurrency.UnownedSerialExecutor {
65+
// CHECK-NEXT: get
66+
// CHECK-NEXT: }
67+
}
68+
}

0 commit comments

Comments
 (0)