Skip to content

Commit 814baea

Browse files
committed
move new enqueue method to be named enqueue and not enqueueOwned
1 parent b6d70db commit 814baea

15 files changed

+164
-78
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6326,7 +6326,7 @@ WARNING(hashvalue_implementation,Deprecation,
63266326

63276327
WARNING(executor_enqueue_unowned_implementation,Deprecation,
63286328
"'Executor.enqueue(UnownedJob)' is deprecated as a protocol requirement; "
6329-
"conform type %0 to 'Executor' by implementing 'enqueueOwned(Job)' instead",
6329+
"conform type %0 to 'Executor' by implementing 'func enqueue(Job)' instead",
63306330
(Type))
63316331

63326332
//------------------------------------------------------------------------------

include/swift/AST/KnownIdentifiers.def

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,6 @@ IDENTIFIER(encodeIfPresent)
8484
IDENTIFIER(Encoder)
8585
IDENTIFIER(encoder)
8686
IDENTIFIER(enqueue)
87-
IDENTIFIER(enqueueOwned)
8887
IDENTIFIER(erasing)
8988
IDENTIFIER(error)
9089
IDENTIFIER(errorDomain)

include/swift/AST/KnownSDKTypes.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ KNOWN_SDK_TYPE_DECL(ObjectiveC, ObjCBool, StructDecl, 0)
3939
// standardized
4040
KNOWN_SDK_TYPE_DECL(Concurrency, UnsafeContinuation, NominalTypeDecl, 2)
4141
KNOWN_SDK_TYPE_DECL(Concurrency, MainActor, NominalTypeDecl, 0)
42+
KNOWN_SDK_TYPE_DECL(Concurrency, Job, StructDecl, 0)
43+
KNOWN_SDK_TYPE_DECL(Concurrency, UnownedJob, StructDecl, 0)
4244
KNOWN_SDK_TYPE_DECL(Concurrency, Executor, NominalTypeDecl, 0)
4345
KNOWN_SDK_TYPE_DECL(Concurrency, SerialExecutor, NominalTypeDecl, 0)
4446
KNOWN_SDK_TYPE_DECL(Concurrency, UnownedSerialExecutor, NominalTypeDecl, 0)

lib/AST/Decl.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5095,7 +5095,7 @@ NominalTypeDecl::getExecutorOwnedEnqueueFunction() const {
50955095

50965096
llvm::SmallVector<ValueDecl *, 2> results;
50975097
lookupQualified(getSelfNominalTypeDecl(),
5098-
DeclNameRef(C.Id_enqueueOwned), // FIXME: make it enqueue
5098+
DeclNameRef(C.Id_enqueue),
50995099
NL_ProtocolMembers,
51005100
results);
51015101

@@ -5104,6 +5104,9 @@ NominalTypeDecl::getExecutorOwnedEnqueueFunction() const {
51045104
if (!isa<ProtocolDecl>(candidate->getDeclContext()))
51055105
continue;
51065106

5107+
fprintf(stderr, "[%s:%d](%s) candidate\n", __FILE_NAME__, __LINE__, __FUNCTION__);
5108+
candidate->dump();
5109+
51075110
if (auto *funcDecl = dyn_cast<AbstractFunctionDecl>(candidate)) {
51085111
if (funcDecl->getParameters()->size() != 1)
51095112
continue;

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 51 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1202,31 +1202,65 @@ void swift::tryDiagnoseExecutorConformance(ASTContext &C,
12021202
Type nominalTy = nominal->getDeclaredInterfaceType();
12031203

12041204
// enqueue(_: UnownedJob)
1205-
auto unownedEnqueueDeclName = DeclName(C, DeclBaseName(C.Id_enqueue), { Identifier() });
1206-
// enqueueOwned(_: Job)
1207-
auto moveOnlyEnqueueDeclName = DeclName(C, DeclBaseName(C.Id_enqueueOwned), { Identifier() });
1205+
auto enqueueDeclName = DeclName(C, DeclBaseName(C.Id_enqueue), { Identifier() });
1206+
1207+
FuncDecl *unownedEnqueueRequirement = nullptr;
1208+
FuncDecl *moveOnlyEnqueueRequirement = nullptr;
1209+
for (auto req: proto->getProtocolRequirements()) {
1210+
auto *funcDecl = dyn_cast<FuncDecl>(req);
1211+
if (!funcDecl)
1212+
continue;
1213+
1214+
if (funcDecl->getName() != enqueueDeclName)
1215+
continue;
1216+
1217+
1218+
// look for the first parameter being a Job or UnownedJob
1219+
if (funcDecl->getParameters()->size() != 1)
1220+
continue;
1221+
if (auto param = funcDecl->getParameters()->front()) {
1222+
if (param->getType()->isEqual(C.getJobDecl()->getDeclaredInterfaceType())) {
1223+
assert(moveOnlyEnqueueRequirement == nullptr);
1224+
moveOnlyEnqueueRequirement = funcDecl;
1225+
} else if (param->getType()->isEqual(C.getUnownedJobDecl()->getDeclaredInterfaceType())) {
1226+
assert(unownedEnqueueRequirement == nullptr);
1227+
unownedEnqueueRequirement = funcDecl;
1228+
}
1229+
}
1230+
1231+
// if we found both, we're done here and break out of the loop
1232+
if (unownedEnqueueRequirement && moveOnlyEnqueueRequirement)
1233+
break; // we're done looking for the requirements
1234+
}
1235+
12081236

12091237
auto conformance = module->lookupConformance(nominalTy, proto);
1210-
auto unownedEnqueueWitness = conformance.getWitnessByName(nominalTy, unownedEnqueueDeclName);
1211-
auto moveOnlyEnqueueWitness = conformance.getWitnessByName(nominalTy, moveOnlyEnqueueDeclName);
1238+
auto concreteConformance = conformance.getConcrete();
1239+
auto unownedEnqueueWitness = concreteConformance->getWitnessDeclRef(unownedEnqueueRequirement);
1240+
auto moveOnlyEnqueueWitness = concreteConformance->getWitnessDeclRef(moveOnlyEnqueueRequirement);
12121241

12131242
if (auto enqueueUnownedDecl = unownedEnqueueWitness.getDecl()) {
12141243
// Old UnownedJob based impl is present, warn about it suggesting the new protocol requirement.
1215-
if (enqueueUnownedDecl->getLoc().isValid())
1244+
if (enqueueUnownedDecl->getLoc().isValid()) {
12161245
diags.diagnose(enqueueUnownedDecl->getLoc(), diag::executor_enqueue_unowned_implementation, nominalTy);
1246+
}
12171247
}
12181248

1219-
if (unownedEnqueueWitness.getDecl()->getLoc().isInvalid() &&
1220-
moveOnlyEnqueueWitness.getDecl()->getLoc().isInvalid()) {
1221-
// Neither old or new implementation have been found, but we provide default impls for them
1222-
// that are mutually recursive, so we must error and suggest implementing the right requirement.
1223-
auto ownedRequirement = C.getExecutorDecl()->getExecutorOwnedEnqueueFunction();
1224-
nominal->diagnose(diag::type_does_not_conform, nominalTy, proto->getDeclaredInterfaceType());
1225-
ownedRequirement->diagnose(diag::no_witnesses,
1226-
getProtocolRequirementKind(ownedRequirement),
1227-
ownedRequirement->getName(),
1228-
proto->getDeclaredInterfaceType(),
1229-
/*AddFixIt=*/true);
1249+
if (auto unownedEnqueueDecl = unownedEnqueueWitness.getDecl()) {
1250+
if (auto moveOnlyEnqueueDecl = moveOnlyEnqueueWitness.getDecl()) {
1251+
if (unownedEnqueueDecl && unownedEnqueueDecl->getLoc().isInvalid() &&
1252+
moveOnlyEnqueueDecl && moveOnlyEnqueueDecl->getLoc().isInvalid()) {
1253+
// Neither old nor new implementation have been found, but we provide default impls for them
1254+
// that are mutually recursive, so we must error and suggest implementing the right requirement.
1255+
auto ownedRequirement = C.getExecutorDecl()->getExecutorOwnedEnqueueFunction();
1256+
nominal->diagnose(diag::type_does_not_conform, nominalTy, proto->getDeclaredInterfaceType());
1257+
ownedRequirement->diagnose(diag::no_witnesses,
1258+
getProtocolRequirementKind(ownedRequirement),
1259+
ownedRequirement->getName(),
1260+
proto->getDeclaredInterfaceType(),
1261+
/*AddFixIt=*/true);
1262+
}
1263+
}
12301264
}
12311265
}
12321266

stdlib/public/BackDeployConcurrency/Actor.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,9 +285,14 @@ JobPriority swift::swift_task_getCurrentThreadPriority() {
285285
SWIFT_CC(swift)
286286
static bool swift_task_isCurrentExecutorImpl(ExecutorRef executor) {
287287
if (auto currentTracking = ExecutorTrackingInfo::current()) {
288+
fprintf(stderr, "[%s:%d](%s) current executor = %p, main:%s, default:%s\n", __FILE_NAME__, __LINE__, __FUNCTION__,
289+
currentTracking->getActiveExecutor().getIdentity(),
290+
currentTracking->getActiveExecutor().isMainExecutor() ? "y" : "n",
291+
currentTracking->getActiveExecutor().isDefaultActor() ? "y" : "n");
288292
return currentTracking->getActiveExecutor() == executor;
289293
}
290294

295+
fprintf(stderr, "[%s:%d](%s) no executor found in tracking\n", __FILE_NAME__, __LINE__, __FUNCTION__);
291296
return executor.isMainExecutor() && isExecutingOnMainThread();
292297
}
293298

stdlib/public/BackDeployConcurrency/Executor.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,10 @@ internal final class DispatchQueueShim: @unchecked Sendable, SerialExecutor {
117117
_enqueueOnDispatchQueue(job, queue: self)
118118
}
119119

120+
func enqueue(_ job: __owned Job) {
121+
_enqueueOnDispatchQueue(job, queue: self)
122+
}
123+
120124
func asUnownedSerialExecutor() -> UnownedSerialExecutor {
121125
return UnownedSerialExecutor(ordinary: self)
122126
}

stdlib/public/BackDeployConcurrency/PartialAsyncTask.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ public struct UnownedJob: Sendable {
3030

3131
@_alwaysEmitIntoClient
3232
@inlinable
33-
@available(*, deprecated, message: "Use SerialExecutor.runJobSynchronously(_:) instead.")
3433
public func _runSynchronously(on executor: UnownedSerialExecutor) {
3534
_swiftJobRun(self, executor)
3635
}

stdlib/public/Concurrency/Executor.swift

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ import Swift
1515
/// A service that can execute jobs.
1616
@available(SwiftStdlib 5.1, *)
1717
public protocol Executor: AnyObject, Sendable {
18-
@available(*, deprecated, message: "Implement enqueueJob instead")
18+
@available(*, deprecated, message: "Implement 'enqueue(_: __owned Job)' instead")
1919
func enqueue(_ job: UnownedJob)
2020

2121
@available(SwiftStdlib 5.9, *)
22-
func enqueueOwned(_ job: __owned Job) // FIXME: figure out how to introduce in compatible way
22+
func enqueue(_ job: __owned Job)
2323
}
2424

2525
/// A service that executes jobs.
@@ -30,7 +30,7 @@ public protocol SerialExecutor: Executor {
3030
// avoid drilling down to the base conformance just for the basic
3131
// work-scheduling operation.
3232
@_nonoverride
33-
@available(*, deprecated, message: "Implement enqueueJob instead")
33+
@available(*, deprecated, message: "Implement 'enqueue_: __owned Job) instead")
3434
func enqueue(_ job: UnownedJob)
3535

3636
// This requirement is repeated here as a non-override so that we
@@ -39,7 +39,7 @@ public protocol SerialExecutor: Executor {
3939
// work-scheduling operation.
4040
@_nonoverride
4141
@available(SwiftStdlib 5.9, *)
42-
func enqueueOwned(_ job: __owned Job) // FIXME: figure out how to introduce in compatible way
42+
func enqueue(_ job: __owned Job)
4343

4444
/// Convert this executor value to the optimized form of borrowed
4545
/// executor references.
@@ -48,15 +48,22 @@ public protocol SerialExecutor: Executor {
4848

4949
@available(SwiftStdlib 5.9, *)
5050
extension Executor {
51-
public func enqueue(_ job: UnownedJob) { // FIXME: this is bad; how could we deploy this nicely
51+
public func enqueue(_ job: UnownedJob) {
5252
fatalError("Please implement \(Self.self).enqueueJob(_:)")
5353
}
5454

55-
public func enqueueOwned(_ job: __owned Job) {
55+
public func enqueue(_ job: __owned Job) {
5656
self.enqueue(UnownedJob(job))
5757
}
5858
}
5959

60+
@available(SwiftStdlib 5.9, *)
61+
extension SerialExecutor {
62+
public func asUnownedSerialExecutor() -> UnownedSerialExecutor {
63+
UnownedSerialExecutor(ordinary: self)
64+
}
65+
}
66+
6067
/// An unowned reference to a serial executor (a `SerialExecutor`
6168
/// value).
6269
///
@@ -121,7 +128,7 @@ internal func _getJobTaskId(_ job: UnownedJob) -> UInt64
121128
internal func _enqueueOnExecutor<E>(job unownedJob: UnownedJob, executor: E)
122129
where E: SerialExecutor {
123130
if #available(SwiftStdlib 5.9, *) {
124-
executor.enqueueOwned(Job(context: unownedJob.context))
131+
executor.enqueue(Job(context: unownedJob.context))
125132
} else {
126133
executor.enqueue(unownedJob)
127134
}

stdlib/public/Concurrency/PartialAsyncTask.swift

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,7 @@ public struct UnownedJob: Sendable {
3434
}
3535

3636
@available(SwiftStdlib 5.9, *)
37-
@usableFromInline
38-
internal init(_ job: __owned Job) {
37+
public init(_ job: __owned Job) {
3938
self.context = job.context
4039
}
4140

@@ -47,6 +46,7 @@ public struct UnownedJob: Sendable {
4746

4847
@_alwaysEmitIntoClient
4948
@inlinable
49+
@available(*, deprecated, renamed: "runSynchronously(on:)")
5050
public func _runSynchronously(on executor: UnownedSerialExecutor) {
5151
_swiftJobRun(self, executor)
5252
}
@@ -90,43 +90,67 @@ public struct Job: Sendable {
9090
// TODO: move only types cannot conform to protocols, so we can't conform to CustomStringConvertible;
9191
// we can still offer a description to be called explicitly though.
9292
public var description: String {
93-
"\(Self.self)(\(_getJobTaskId(UnownedJob(context: self.context)))"
93+
let id = _getJobTaskId(UnownedJob(context: self.context))
94+
/// Tasks are always assigned an unique ID, however some jobs may not have it set,
95+
/// and it appearing as 0 for _different_ jobs may lead to misunderstanding it as
96+
/// being "the same 0 id job", we specifically print 0 (id not set) as nil.
97+
if (id > 0) {
98+
return "\(Self.self)(id: \(id))"
99+
} else {
100+
return "\(Self.self)(id: nil)"
101+
}
94102
}
95103
}
96104

97105
@available(SwiftStdlib 5.9, *)
98-
extension UnownedSerialExecutor {
106+
extension Job {
107+
99108
/// Run the job synchronously.
100109
///
101-
/// This operation consumes the job.
110+
/// This operation consumes the job, preventing it accidental use after it has ben run.
111+
///
112+
/// Converting a `Job` to an `UnownedJob` and invoking `runSynchronously` on it multiple times is undefined behavior,
113+
/// as a job can only ever be run once, and must not be accessed after it has been run.
102114
@_alwaysEmitIntoClient
103115
@inlinable
104-
public func runJobSynchronously(_ job: __owned Job) {
105-
_swiftJobRun(UnownedJob(job), self)
116+
__consuming public func runSynchronously(on executor: some SerialExecutor) {
117+
_swiftJobRun(UnownedJob(self), UnownedSerialExecutor(ordinary: executor))
106118
}
107119

120+
/// Run the job synchronously.
121+
///
122+
/// This operation consumes the job, preventing it accidental use after it has ben run.
123+
///
124+
/// Converting a `Job` to an `UnownedJob` and invoking `runSynchronously` on it multiple times is undefined behavior,
125+
/// as a job can only ever be run once, and must not be accessed after it has been run.
108126
@_alwaysEmitIntoClient
109127
@inlinable
110-
public func runUnownedJobSynchronously(_ job: UnownedJob) {
111-
_swiftJobRun(job, self)
128+
__consuming public func runSynchronously(on executor: UnownedSerialExecutor) {
129+
_swiftJobRun(UnownedJob(self), executor)
112130
}
113131
}
114132

115133
@available(SwiftStdlib 5.9, *)
116-
extension SerialExecutor {
134+
extension UnownedJob {
135+
117136
/// Run the job synchronously.
118137
///
119-
/// This operation consumes the job.
138+
/// Invoking `runSynchronously` on a job multiple times is undefined behavior,
139+
/// as a job can only ever be run once, and must not be accessed after it has been run.
120140
@_alwaysEmitIntoClient
121141
@inlinable
122-
public func runJobSynchronously(_ job: __owned Job) {
123-
_swiftJobRun(UnownedJob(job), self.asUnownedSerialExecutor())
142+
__consuming public func runSynchronously(on executor: some SerialExecutor) {
143+
_swiftJobRun(self, UnownedSerialExecutor(ordinary: executor))
124144
}
125145

146+
/// Run the job synchronously.
147+
///
148+
/// Invoking `runSynchronously` on a job multiple times is undefined behavior,
149+
/// as a job can only ever be run once, and must not be accessed after it has been run.
126150
@_alwaysEmitIntoClient
127151
@inlinable
128-
public func runUnownedJobSynchronously(_ job: UnownedJob) {
129-
_swiftJobRun(job, self.asUnownedSerialExecutor())
152+
__consuming public func runSynchronously(on executor: UnownedSerialExecutor) {
153+
_swiftJobRun(self, executor)
130154
}
131155
}
132156

test/Concurrency/Runtime/custom_executors.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-run-simple-swift( -Xfrontend -disable-availability-checking %import-libdispatch -parse-as-library) | %FileCheck %s
1+
// RUN: %target-run-simple-swift( -Xfrontend -enable-experimental-move-only -Xfrontend -disable-availability-checking %import-libdispatch -parse-as-library) | %FileCheck %s --dump-input=always
22

33
// REQUIRES: concurrency
44
// REQUIRES: executable_test

test/Concurrency/Runtime/custom_executors_moveOnly_job.swift

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,8 @@
88
// REQUIRES: concurrency_runtime
99

1010
final class InlineExecutor: SerialExecutor, CustomStringConvertible {
11-
12-
public func enqueueOwned(_ job: __owned Job) {
13-
runJobSynchronously(job)
14-
}
15-
16-
public func asUnownedSerialExecutor() -> UnownedSerialExecutor {
17-
return UnownedSerialExecutor(ordinary: self)
11+
public func enqueue(_ job: __owned Job) {
12+
job.runSynchronously(on: self)
1813
}
1914

2015
var description: Swift.String {

test/Concurrency/Runtime/custom_executors_priority.swift

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-run-simple-swift( -Xfrontend -disable-availability-checking %import-libdispatch -parse-as-library) | %FileCheck %s
1+
// RUN: %target-run-simple-swift( -Xfrontend -enable-experimental-move-only -Xfrontend -disable-availability-checking %import-libdispatch -parse-as-library) | %FileCheck %s
22

33
// REQUIRES: concurrency
44
// REQUIRES: executable_test
@@ -8,13 +8,9 @@
88
// REQUIRES: concurrency_runtime
99

1010
final class InlineExecutor: SerialExecutor {
11-
public func enqueue(_ job: UnownedJob) {
11+
public func enqueue(_ job: __owned Job) {
1212
print("\(self): enqueue (priority: \(job.priority.asTaskPriority!))")
13-
job._runSynchronously(on: self.asUnownedSerialExecutor())
14-
}
15-
16-
public func asUnownedSerialExecutor() -> UnownedSerialExecutor {
17-
return UnownedSerialExecutor(ordinary: self)
13+
job.runSynchronously(on: self)
1814
}
1915
}
2016

@@ -46,8 +42,6 @@ actor Custom {
4642
await actor.report()
4743
}.value
4844
await Task(priority: .low) {
49-
print("P: \(Task.currentPriority)")
50-
print("B: \(Task.basePriority)")
5145
await actor.report()
5246
}.value
5347
print("end")

0 commit comments

Comments
 (0)