From a2dee560958db97eb0c5b693d27d2a9402358ac8 Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Tue, 19 Sep 2023 17:46:18 +0900 Subject: [PATCH] Avoid issuing warning when user lib implements only ExecutorJob enqueue The latter example NIODefaultSerialEventLoopExecutor when the type is more available than the enqueue implementation provided via an extrension would issue a warning that that this enqueue(ExecutorJob) would not be used which is not true. We need to filter out all "default impls" from the stdlib as we issue this warning. We also put a note on the offending declaration that one can remove now, to ease getting rid of warnings when possible Resolves rdar://115166475 --- lib/Sema/TypeCheckConcurrency.cpp | 6 +- ...custom_executor_enqueue_availability.swift | 2 +- test/Concurrency/radar_concurrency_nio.swift | 66 +++++++++++++++++++ 3 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 test/Concurrency/radar_concurrency_nio.swift diff --git a/lib/Sema/TypeCheckConcurrency.cpp b/lib/Sema/TypeCheckConcurrency.cpp index 8562119e8c239..29553130c1170 100644 --- a/lib/Sema/TypeCheckConcurrency.cpp +++ b/lib/Sema/TypeCheckConcurrency.cpp @@ -1394,9 +1394,13 @@ void swift::tryDiagnoseExecutorConformance(ASTContext &C, // If both old and new enqueue are implemented, but the old one cannot be removed, // emit a warning that the new enqueue is unused. if (!canRemoveOldDecls && unownedEnqueueWitnessDecl && moveOnlyEnqueueWitnessDecl) { - if (!isStdlibDefaultImplDecl(moveOnlyEnqueueWitnessDecl)) { + if (!isStdlibDefaultImplDecl(moveOnlyEnqueueWitnessDecl) && + !isStdlibDefaultImplDecl(unownedEnqueueWitnessDecl)) { diags.diagnose(moveOnlyEnqueueWitnessDecl->getLoc(), diag::executor_enqueue_unused_implementation); + if (auto decl = unownedEnqueueWitnessDecl) { + decl->diagnose(diag::decl_declared_here, decl); + } } } diff --git a/test/Concurrency/custom_executor_enqueue_availability.swift b/test/Concurrency/custom_executor_enqueue_availability.swift index 37b150d7135f9..10f334daf0833 100644 --- a/test/Concurrency/custom_executor_enqueue_availability.swift +++ b/test/Concurrency/custom_executor_enqueue_availability.swift @@ -26,7 +26,7 @@ final class OldExecutorOldStdlib: SerialExecutor { /// availability, since in this case the UnownedJob version needs to exist. @available(SwiftStdlib 5.1, *) final class BothExecutorOldStdlib: SerialExecutor { - func enqueue(_ job: UnownedJob) {} + func enqueue(_ job: UnownedJob) {} // expected-note{{'enqueue' declared here}} @available(SwiftStdlib 5.9, *) func enqueue(_ job: __owned ExecutorJob) {} // expected-warning{{'Executor.enqueue(ExecutorJob)' will never be used, due to the presence of 'enqueue(UnownedJob)'}} diff --git a/test/Concurrency/radar_concurrency_nio.swift b/test/Concurrency/radar_concurrency_nio.swift new file mode 100644 index 0000000000000..9dd20290c4dba --- /dev/null +++ b/test/Concurrency/radar_concurrency_nio.swift @@ -0,0 +1,66 @@ +// RUN: %target-swift-frontend -enable-experimental-move-only %s -emit-sil -o /dev/null -verify +// RUN: %target-swift-frontend -enable-experimental-move-only %s -emit-sil -o /dev/null -verify -strict-concurrency=targeted +// RUN: %target-swift-frontend -enable-experimental-move-only %s -emit-sil -o /dev/null -verify -strict-concurrency=complete +// RUN: %target-swift-frontend -enable-experimental-move-only %s -emit-sil -o /dev/null -verify -strict-concurrency=complete -enable-experimental-feature SendNonSendable + +// REQUIRES: concurrency + +public protocol EventLoop: Sendable {} + +#if compiler(>=5.9) +/// A helper protocol that can be mixed in to a NIO ``EventLoop`` to provide an +/// automatic conformance to `SerialExecutor`. +/// +/// Implementers of `EventLoop` should consider conforming to this protocol as +/// well on Swift 5.9 and later. +@available(macOS 14.0, iOS 17.0, watchOS 10.0, tvOS 17.0, *) +public protocol NIOSerialEventLoopExecutor: EventLoop, SerialExecutor { } + +@available(macOS 14.0, iOS 17.0, watchOS 10.0, tvOS 17.0, *) +extension NIOSerialEventLoopExecutor { + @inlinable + public func enqueue(_ job: consuming ExecutorJob) { + fatalError("mock impl") + } + + @inlinable + public func asUnownedSerialExecutor() -> UnownedSerialExecutor { + UnownedSerialExecutor(ordinary: self) + } + + @inlinable + public var executor: any SerialExecutor { + self + } +} + +// EARLIER AVAILABILITY +final class NIODefaultSerialEventLoopExecutor { + @usableFromInline + let loop: EventLoop + + @inlinable + init(_ loop: EventLoop) { + self.loop = loop + } +} + +@available(macOS 14.0, iOS 17.0, watchOS 10.0, tvOS 17.0, *) +extension NIODefaultSerialEventLoopExecutor: SerialExecutor { + @inlinable + public func enqueue(_ job: consuming ExecutorJob) { // do NOT issue a warning here + fatalError("mock impl") + } + + @inlinable + public func asUnownedSerialExecutor() -> UnownedSerialExecutor { + UnownedSerialExecutor(complexEquality: self) + + } + + @inlinable + public func isSameExclusiveExecutionContext(other: NIODefaultSerialEventLoopExecutor) -> Bool { + false + } +} +#endif