[Concurrency] Adopt stable keyword consuming instead of __owned

add test for warnings emitted when missing consuming attribute

use -emit-sil in mock SDK tests for better coverage
This commit is contained in:
Konrad `ktoso` Malawski
2023-05-01 20:37:38 +09:00
parent 6877778fad
commit da6f08a24e
15 changed files with 111 additions and 17 deletions

View File

@@ -5416,11 +5416,12 @@ NominalTypeDecl::getExecutorLegacyUnownedEnqueueFunction() const {
if (auto *funcDecl = dyn_cast<AbstractFunctionDecl>(candidate)) {
auto params = funcDecl->getParameters();
if (params->size() != 1)
continue;
if (params->get(0)->getType()->isEqual(unownedJobDecl->getDeclaredInterfaceType())) {
auto param = params->get(0);
if (param->getSpecifier() == ParamSpecifier::LegacyOwned ||
param->getSpecifier() == ParamSpecifier::Consuming) {
return funcDecl;
}
}

View File

@@ -29,12 +29,12 @@ public protocol Executor: AnyObject, Sendable {
#if !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
@available(SwiftStdlib 5.9, *)
@available(*, deprecated, message: "Implement 'enqueue(_: __owned ExecutorJob)' instead")
func enqueue(_ job: __owned Job)
func enqueue(_ job: consuming Job)
#endif // !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
#if !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
@available(SwiftStdlib 5.9, *)
func enqueue(_ job: __owned ExecutorJob)
func enqueue(_ job: consuming ExecutorJob)
#endif // !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
}
@@ -60,7 +60,7 @@ public protocol SerialExecutor: Executor {
@_nonoverride
@available(SwiftStdlib 5.9, *)
@available(*, deprecated, message: "Implement 'enqueue(_: __owned ExecutorJob)' instead")
func enqueue(_ job: __owned Job)
func enqueue(_ job: consuming Job)
#endif // !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
#if !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
@@ -70,7 +70,7 @@ public protocol SerialExecutor: Executor {
// work-scheduling operation.
@_nonoverride
@available(SwiftStdlib 5.9, *)
func enqueue(_ job: __owned ExecutorJob)
func enqueue(_ job: consuming ExecutorJob)
#endif // !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
/// Convert this executor value to the optimized form of borrowed
@@ -110,11 +110,11 @@ extension Executor {
self.enqueue(ExecutorJob(job))
}
public func enqueue(_ job: __owned ExecutorJob) {
public func enqueue(_ job: consuming ExecutorJob) {
self.enqueue(Job(job))
}
public func enqueue(_ job: __owned Job) {
public func enqueue(_ job: consuming Job) {
self.enqueue(UnownedJob(job))
}
}

View File

@@ -45,7 +45,7 @@ public struct UnownedJob: Sendable {
#if !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
/// Create an `UnownedJob` whose lifetime must be managed carefully until it is run exactly once.
@available(SwiftStdlib 5.9, *)
public init(_ job: __owned Job) {
public init(_ job: __owned Job) { // must remain '__owned' in order to not break ABI
self.context = job.context
}
#endif // !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
@@ -53,7 +53,7 @@ public struct UnownedJob: Sendable {
#if !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
/// Create an `UnownedJob` whose lifetime must be managed carefully until it is run exactly once.
@available(SwiftStdlib 5.9, *)
public init(_ job: __owned ExecutorJob) {
public init(_ job: __owned ExecutorJob) { // must remain '__owned' in order to not break ABI
self.context = job.context
}
#endif // !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY

View File

@@ -24,7 +24,7 @@ internal final class DistributedRemoteActorReferenceExecutor: SerialExecutor {
internal init() {}
@inlinable
public func enqueue(_ job: __owned ExecutorJob) {
public func enqueue(_ job: consuming ExecutorJob) {
let jobDescription = job.description
fatalError("Attempted to enqueue ExecutorJob (\(jobDescription)) on executor of remote distributed actor reference!")
}

View File

@@ -23,7 +23,7 @@ final class NaiveQueueExecutor: SerialExecutor, CustomStringConvertible {
self.queue = queue
}
public func enqueue(_ job: __owned ExecutorJob) {
public func enqueue(_ job: consuming ExecutorJob) {
let unowned = UnownedJob(job)
queue.sync {
unowned.runSynchronously(on: self.asUnownedSerialExecutor())

View File

@@ -9,6 +9,7 @@
// UNSUPPORTED: back_deployment_runtime
// REQUIRES: concurrency_runtime
@available(*, deprecated, message: "Test type to verify deprecated API still works")
final class InlineExecutor_UnownedJob: SerialExecutor, CustomStringConvertible {
public func enqueue(_ job: UnownedJob) {
job.runSynchronously(on: self.asUnownedSerialExecutor())
@@ -18,6 +19,8 @@ final class InlineExecutor_UnownedJob: SerialExecutor, CustomStringConvertible {
"\(Self.self)()"
}
}
@available(*, deprecated, message: "Test type to verify deprecated API still works")
final class InlineExecutor_Job: SerialExecutor, CustomStringConvertible {
public func enqueue(_ job: __owned Job) {
job.runSynchronously(on: self.asUnownedSerialExecutor())

View File

@@ -10,7 +10,7 @@
// REQUIRES: concurrency_runtime
final class InlineExecutor: SerialExecutor {
public func enqueue(_ job: __owned ExecutorJob) {
public func enqueue(_ job: consuming ExecutorJob) {
print("\(self): enqueue (priority: \(TaskPriority(job.priority)!))")
job.runSynchronously(on: self.asUnownedSerialExecutor())
}

View File

@@ -35,7 +35,7 @@ final class NaiveQueueExecutor: SpecifiedExecutor, CustomStringConvertible {
self.queue = queue
}
public func enqueue(_ job: __owned ExecutorJob) {
public func enqueue(_ job: consuming ExecutorJob) {
print("\(self): enqueue")
let unowned = UnownedJob(job)
queue.sync {

View File

@@ -0,0 +1,18 @@
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-concurrency-consuming-job-param) -emit-sil -parse-as-library %s -verify
// REQUIRES: concurrency
// REQUIRES: libdispatch
// rdar://106849189 move-only types should be supported in freestanding mode
// UNSUPPORTED: freestanding
// UNSUPPORTED: back_deployment_runtime
// REQUIRES: concurrency_runtime
import _Concurrency
final class FakeExecutor: SerialExecutor {
// implements the __owned requirement in "old" SDK:
// func enqueue(_ job: __owned Job)
func enqueue(_ job: __owned ExecutorJob) {}
}

View File

@@ -0,0 +1,18 @@
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-concurrency-owned-job-param) -emit-sil -parse-as-library %s -verify
// REQUIRES: concurrency
// REQUIRES: libdispatch
// rdar://106849189 move-only types should be supported in freestanding mode
// UNSUPPORTED: freestanding
// UNSUPPORTED: back_deployment_runtime
// REQUIRES: concurrency_runtime
import _Concurrency
final class FakeExecutor: SerialExecutor {
// implements the __owned requirement in "old" SDK:
// func enqueue(_ job: __owned Job)
func enqueue(_ job: consuming ExecutorJob) {}
}

View File

@@ -1,4 +1,4 @@
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-concurrency-without-job) -typecheck -parse-as-library %s -verify
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-concurrency-without-job) -emit-sil -parse-as-library %s -verify
// REQUIRES: concurrency
// REQUIRES: libdispatch

View File

@@ -41,7 +41,7 @@ final class TripleExecutor: SerialExecutor {
// expected-note@+1{{use 'ExecutorJob' instead}}
func enqueue(_ job: __owned Job) {} // expected-warning{{'Executor.enqueue(Job)' is deprecated as a protocol requirement; conform type 'TripleExecutor' to 'Executor' by implementing 'func enqueue(ExecutorJob)' instead}}
func enqueue(_ job: __owned ExecutorJob) {}
func enqueue(_ job: consuming ExecutorJob) {}
func asUnownedSerialExecutor() -> UnownedSerialExecutor {
UnownedSerialExecutor(ordinary: self)
@@ -72,7 +72,19 @@ final class StillDeprecated: SerialExecutor {
/// Just implementing the new signature causes no warnings, good.
final class NewExecutor: SerialExecutor {
func enqueue(_ job: __owned ExecutorJob) {} // no warnings
func enqueue(_ job: consuming ExecutorJob) {} // no warnings
func asUnownedSerialExecutor() -> UnownedSerialExecutor {
UnownedSerialExecutor(ordinary: self)
}
}
// Good impl, but missing the ownership keyword
final class MissingOwnership: SerialExecutor {
func enqueue(_ job: ExecutorJob) {} // expected-error{{noncopyable parameter must specify its ownership}}
// expected-note@-1{{add 'borrowing' for an immutable reference}}
// expected-note@-2{{add 'inout' for a mutable reference}}
// expected-note@-3{{add 'consuming' to take the value from the caller}}
func asUnownedSerialExecutor() -> UnownedSerialExecutor {
UnownedSerialExecutor(ordinary: self)

View File

@@ -0,0 +1,11 @@
// This simulates a pre-Swift5.9 concurrency library with an consuming declaration rather than __owned.
// This allows us to confirm the compiler and sdk can be mismatched but we'll build correctly.
@_moveOnly
public struct ExecutorJob {}
public protocol SerialExecutor {
// pretend old SDK with `__owned` param rather than ``
func enqueue(_ job: consuming ExecutorJob)
}

View File

@@ -0,0 +1,11 @@
// This simulates a pre-Swift5.9 concurrency library with an __owned declaration rather than consuming.
// This allows us to confirm the compiler and sdk can be mismatched but we'll build correctly.
@_moveOnly
public struct ExecutorJob {}
public protocol SerialExecutor {
// pretend old SDK with `__owned` param rather than ``
func enqueue(_ job: __owned ExecutorJob)
}

View File

@@ -634,6 +634,26 @@ config.substitutions.append(('%clang-importer-sdk-concurrency-typealias-struct-j
'-enable-source-import -sdk %r -I %r ' % (make_path(config.test_source_root, 'Inputs', 'clang-importer-sdk'),
make_path(config.test_source_root, 'Inputs', 'clang-importer-sdk', 'swift-modules-concurrency-typealias-struct-job'))))
# FIXME: BEGIN -enable-source-import hackaround
config.substitutions.append(('%clang-importer-sdk-concurrency-consuming-job-param-path',
'%r' % (make_path(config.test_source_root, 'Inputs', 'clang-importer-sdk'))))
config.substitutions.append(('%clang-importer-sdk-concurrency-consuming-job-param-nosource',
'-sdk %r' % (make_path(config.test_source_root, 'Inputs', 'clang-importer-sdk'))))
# FIXME: END -enable-source-import hackaround
config.substitutions.append(('%clang-importer-sdk-concurrency-consuming-job-param',
'-enable-source-import -sdk %r -I %r ' % (make_path(config.test_source_root, 'Inputs', 'clang-importer-sdk'),
make_path(config.test_source_root, 'Inputs', 'clang-importer-sdk', 'swift-modules-concurrency-consuming-job-param'))))
# FIXME: BEGIN -enable-source-import hackaround
config.substitutions.append(('%clang-importer-sdk-concurrency-owned-job-param-path',
'%r' % (make_path(config.test_source_root, 'Inputs', 'clang-importer-sdk'))))
config.substitutions.append(('%clang-importer-sdk-concurrency-owned-job-param-nosource',
'-sdk %r' % (make_path(config.test_source_root, 'Inputs', 'clang-importer-sdk'))))
# FIXME: END -enable-source-import hackaround
config.substitutions.append(('%clang-importer-sdk-concurrency-owned-job-param',
'-enable-source-import -sdk %r -I %r ' % (make_path(config.test_source_root, 'Inputs', 'clang-importer-sdk'),
make_path(config.test_source_root, 'Inputs', 'clang-importer-sdk', 'swift-modules-concurrency-owned-job-param'))))
# FIXME: BEGIN -enable-source-import hackaround
config.substitutions.append(('%clang-importer-sdk-path',
'%r' % (make_path(config.test_source_root, 'Inputs', 'clang-importer-sdk'))))