Skip to content

Commit c499dd2

Browse files
committed
[Sema] Improve SerialExecutor diagnostics
1 parent da34a4e commit c499dd2

File tree

3 files changed

+54
-6
lines changed

3 files changed

+54
-6
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6676,6 +6676,10 @@ WARNING(executor_enqueue_deprecated_owned_job_implementation,Deprecation,
66766676
"'Executor.enqueue(Job)' is deprecated as a protocol requirement; "
66776677
"conform type %0 to 'Executor' by implementing 'func enqueue(ExecutorJob)' instead",
66786678
(Type))
6679+
WARNING(executor_enqueue_unused_implementation, none,
6680+
"'Executor.enqueue(ExecutorJob)' will never be used, due to the presence of "
6681+
"'enqueue(UnownedJob)'",
6682+
(Type))
66796683

66806684
//------------------------------------------------------------------------------
66816685
// MARK: property wrapper diagnostics

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1334,10 +1334,18 @@ void swift::tryDiagnoseExecutorConformance(ASTContext &C,
13341334
ValueDecl *unownedEnqueueWitnessDecl = unownedEnqueueWitness.getDecl();
13351335
ValueDecl *moveOnlyEnqueueWitnessDecl = nullptr;
13361336
ValueDecl *legacyMoveOnlyEnqueueWitnessDecl = nullptr;
1337+
// true iff the nominal type's availability allows the legacy requirement
1338+
// to be omitted in favor of moveOnlyEnqueueRequirement
1339+
bool canRemoveOldDecls = false;
13371340

13381341
if (moveOnlyEnqueueRequirement) {
13391342
moveOnlyEnqueueWitnessDecl = concreteConformance->getWitnessDeclRef(
13401343
moveOnlyEnqueueRequirement).getDecl();
1344+
AvailabilityContext requirementInfo
1345+
= AvailabilityInference::availableRange(moveOnlyEnqueueRequirement, C);
1346+
AvailabilityContext declInfo =
1347+
TypeChecker::overApproximateAvailabilityAtLocation(nominal->getLoc(), dyn_cast<DeclContext>(nominal));
1348+
canRemoveOldDecls = declInfo.isContainedIn(requirementInfo);
13411349
}
13421350
if (legacyMoveOnlyEnqueueRequirement) {
13431351
legacyMoveOnlyEnqueueWitnessDecl = concreteConformance->getWitnessDeclRef(
@@ -1346,8 +1354,14 @@ void swift::tryDiagnoseExecutorConformance(ASTContext &C,
13461354

13471355
// --- Diagnose warnings and errors
13481356

1357+
if (!canRemoveOldDecls &&
1358+
unownedEnqueueWitnessDecl && unownedEnqueueWitnessDecl->getLoc().isValid() &&
1359+
moveOnlyEnqueueWitnessDecl && moveOnlyEnqueueWitnessDecl->getLoc().isValid()) {
1360+
diags.diagnose(moveOnlyEnqueueWitnessDecl->getLoc(), diag::executor_enqueue_unused_implementation, nominalTy);
1361+
}
1362+
13491363
// Old UnownedJob based impl is present, warn about it suggesting the new protocol requirement.
1350-
if (unownedEnqueueWitnessDecl && unownedEnqueueWitnessDecl->getLoc().isValid()) {
1364+
if (canRemoveOldDecls && unownedEnqueueWitnessDecl && unownedEnqueueWitnessDecl->getLoc().isValid()) {
13511365
diags.diagnose(unownedEnqueueWitnessDecl->getLoc(), diag::executor_enqueue_unowned_implementation, nominalTy);
13521366
}
13531367
// Old Job based impl is present, warn about it suggesting the new protocol requirement.

test/Concurrency/custom_executor_enqueue_impls.swift

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-typecheck-verify-swift -enable-experimental-move-only -disable-availability-checking
1+
// RUN: %target-typecheck-verify-swift -enable-experimental-move-only
22
// REQUIRES: concurrency
33

44
// rdar://106849189 move-only types should be supported in freestanding mode
@@ -7,10 +7,8 @@
77
// FIXME: rdar://107112715 test failing on iOS simulator, investigating
88
// UNSUPPORTED: OS=ios
99

10-
// Such type may be encountered since Swift 5.5 (5.1 backdeployed) if someone implemented the
11-
// not documented, but public Executor types back then already.
12-
//
13-
// We keep support for them, but also log a deprecation warning that they should move to the new signature.
10+
// If the availability is recent enough, log a deprecation warning to move to the new signature.
11+
@available(SwiftStdlib 5.9, *)
1412
final class OldExecutor: SerialExecutor {
1513
func enqueue(_ job: UnownedJob) {} // expected-warning{{'Executor.enqueue(UnownedJob)' is deprecated as a protocol requirement; conform type 'OldExecutor' to 'Executor' by implementing 'func enqueue(ExecutorJob)' instead}}
1614

@@ -19,10 +17,23 @@ final class OldExecutor: SerialExecutor {
1917
}
2018
}
2119

20+
/// Such a type may be encountered since Swift 5.5 (5.1 backdeployed) if someone implemented the
21+
/// not documented, but public Executor types back then already. Allow these to be implemented
22+
/// without warnings.
23+
@available(SwiftStdlib 5.1, *)
24+
final class OldExecutorOldStdlib: SerialExecutor {
25+
func enqueue(_ job: UnownedJob) {}
26+
27+
func asUnownedSerialExecutor() -> UnownedSerialExecutor {
28+
UnownedSerialExecutor(ordinary: self)
29+
}
30+
}
31+
2232
/// Implementing both enqueue methods is legal, but somewhat useless --
2333
/// we call into the "old one"; so the Owned version is not used in such impl.
2434
///
2535
/// That's why we do log the deprecation warning, people should use the move-only version.
36+
@available(SwiftStdlib 5.9, *)
2637
final class BothExecutor: SerialExecutor {
2738
func enqueue(_ job: UnownedJob) {} // expected-warning{{'Executor.enqueue(UnownedJob)' is deprecated as a protocol requirement; conform type 'BothExecutor' to 'Executor' by implementing 'func enqueue(ExecutorJob)' instead}}
2839

@@ -33,7 +44,22 @@ final class BothExecutor: SerialExecutor {
3344
}
3445
}
3546

47+
/// Meanwhile, we warn on the ExecutorJob witness if the type has a broader
48+
/// availability, since in this case the UnownedJob version needs to exist.
49+
@available(SwiftStdlib 5.1, *)
50+
final class BothExecutorOld: SerialExecutor {
51+
func enqueue(_ job: UnownedJob) {}
52+
53+
@available(SwiftStdlib 5.9, *)
54+
func enqueue(_ job: __owned ExecutorJob) {} // expected-warning{{'Executor.enqueue(ExecutorJob)' will never be used, due to the presence of 'enqueue(UnownedJob)'}}
55+
56+
func asUnownedSerialExecutor() -> UnownedSerialExecutor {
57+
UnownedSerialExecutor(ordinary: self)
58+
}
59+
}
60+
3661
/// For now we must keep all 3 implementation kinds and warn about deprecated ones
62+
@available(SwiftStdlib 5.9, *)
3763
final class TripleExecutor: SerialExecutor {
3864
func enqueue(_ job: UnownedJob) {} // expected-warning{{'Executor.enqueue(UnownedJob)' is deprecated as a protocol requirement; conform type 'TripleExecutor' to 'Executor' by implementing 'func enqueue(ExecutorJob)' instead}}
3965

@@ -52,6 +78,7 @@ final class TripleExecutor: SerialExecutor {
5278
/// we manually detect and emit an error if neither of them is implemented.
5379
///
5480
/// We do so because we implement them recursively, so one of them must be implemented basically.
81+
@available(SwiftStdlib 5.9, *)
5582
final class NoneExecutor: SerialExecutor { // expected-error{{type 'NoneExecutor' does not conform to protocol 'Executor'}}
5683

5784
func asUnownedSerialExecutor() -> UnownedSerialExecutor {
@@ -60,6 +87,7 @@ final class NoneExecutor: SerialExecutor { // expected-error{{type 'NoneExecutor
6087
}
6188

6289
/// Job still is deprecated
90+
@available(SwiftStdlib 5.9, *)
6391
final class StillDeprecated: SerialExecutor {
6492
// expected-warning@+2{{'Job' is deprecated: renamed to 'ExecutorJob'}}
6593
// expected-note@+1{{use 'ExecutorJob' instead}}
@@ -71,6 +99,7 @@ final class StillDeprecated: SerialExecutor {
7199
}
72100

73101
/// Just implementing the new signature causes no warnings, good.
102+
@available(SwiftStdlib 5.9, *)
74103
final class NewExecutor: SerialExecutor {
75104
func enqueue(_ job: consuming ExecutorJob) {} // no warnings
76105

@@ -80,6 +109,7 @@ final class NewExecutor: SerialExecutor {
80109
}
81110

82111
// Good impl, but missing the ownership keyword
112+
@available(SwiftStdlib 5.9, *)
83113
final class MissingOwnership: SerialExecutor {
84114
func enqueue(_ job: ExecutorJob) {} // expected-error{{noncopyable parameter must specify its ownership}}
85115
// expected-note@-1{{add 'borrowing' for an immutable reference}}

0 commit comments

Comments
 (0)