Browse Source

Enable Swift 6 language mode for more modules (#1985)

Motivation:

v2 will support Swift 6 only. We should enable the Swift 6 language mode
across all v2 modules. This has mostly been done already for non-test
modules. This change enables it for test modules as well.

Modifications:

Enable Swift 6 language mode and existential any for test modules
Result:

Closer to fully supporting Swift 6 language mode
George Barnett 1 year ago
parent
commit
49aec4ebd8

+ 7 - 4
Sources/GRPCHTTP2Core/Internal/Timer.swift

@@ -16,7 +16,7 @@
 
 import NIOCore
 
-struct Timer {
+package struct Timer {
   /// The delay to wait before running the task.
   private let delay: TimeAmount
   /// The task to run, if scheduled.
@@ -38,14 +38,17 @@ struct Timer {
     }
   }
 
-  init(delay: TimeAmount, repeat: Bool = false) {
+  package init(delay: TimeAmount, repeat: Bool = false) {
     self.delay = delay
     self.task = nil
     self.repeat = `repeat`
   }
 
   /// Schedule a task on the given `EventLoop`.
-  mutating func schedule(on eventLoop: any EventLoop, work: @escaping @Sendable () throws -> Void) {
+  package mutating func schedule(
+    on eventLoop: any EventLoop,
+    work: @escaping @Sendable () throws -> Void
+  ) {
     self.task?.cancel()
 
     if self.repeat {
@@ -60,7 +63,7 @@ struct Timer {
   }
 
   /// Cancels the task, if one was scheduled.
-  mutating func cancel() {
+  package mutating func cancel() {
     self.task?.cancel()
     self.task = nil
   }

+ 1 - 13
Tests/GRPCHTTP2CoreTests/Client/Connection/Connection+Equatable.swift

@@ -18,18 +18,7 @@ import GRPCCore
 import GRPCHTTP2Core
 
 // Equatable conformance for these types is 'best effort', this is sufficient for testing but not
-// for general use. As such the conformance is added in the test module and must be declared
-// as a `@retroactive` conformance.
-#if compiler(>=6.0)
-@available(macOS 14.0, iOS 17.0, watchOS 10.0, tvOS 17.0, *)
-extension Connection.Event: @retroactive Equatable {}
-@available(macOS 14.0, iOS 17.0, watchOS 10.0, tvOS 17.0, *)
-extension Connection.CloseReason: @retroactive Equatable {}
-
-extension ClientConnectionEvent: @retroactive Equatable {}
-extension ClientConnectionEvent.CloseReason: @retroactive Equatable {}
-
-#else
+// for general use.
 @available(macOS 14.0, iOS 17.0, watchOS 10.0, tvOS 17.0, *)
 extension Connection.Event: Equatable {}
 @available(macOS 14.0, iOS 17.0, watchOS 10.0, tvOS 17.0, *)
@@ -37,7 +26,6 @@ extension Connection.CloseReason: Equatable {}
 
 extension ClientConnectionEvent: Equatable {}
 extension ClientConnectionEvent.CloseReason: Equatable {}
-#endif
 
 @available(macOS 14.0, iOS 17.0, watchOS 10.0, tvOS 17.0, *)
 extension Connection.Event {

+ 2 - 2
Tests/GRPCHTTP2CoreTests/Client/Connection/ConnectionTests.swift

@@ -204,9 +204,9 @@ final class ConnectionTests: XCTestCase {
 
 extension ClientBootstrap {
   @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
-  func connect<T>(
+  func connect<T: Sendable>(
     to address: GRPCHTTP2Core.SocketAddress,
-    _ configure: @Sendable @escaping (Channel) -> EventLoopFuture<T>
+    _ configure: @Sendable @escaping (any Channel) -> EventLoopFuture<T>
   ) async throws -> T {
     if let ipv4 = address.ipv4 {
       return try await self.connect(

+ 1 - 1
Tests/GRPCHTTP2CoreTests/Client/Connection/LoadBalancers/LoadBalancerTest.swift

@@ -86,7 +86,7 @@ enum LoadBalancerTest {
   ) async throws {
     enum TestEvent {
       case timedOut
-      case completed(Result<Void, Error>)
+      case completed(Result<Void, any Error>)
     }
 
     try await withThrowingTaskGroup(of: TestEvent.self) { group in

+ 13 - 11
Tests/GRPCHTTP2CoreTests/Client/Connection/Utilities/ConnectionTest.swift

@@ -29,7 +29,7 @@ enum ConnectionTest {
   }
 
   static func run(
-    connector: HTTP2Connector,
+    connector: any HTTP2Connector,
     server mode: Server.Mode = .regular,
     handlEvents: (
       _ context: Context,
@@ -67,10 +67,10 @@ extension ConnectionTest {
   final class Server {
     private let eventLoop: any EventLoop
     private var listener: (any Channel)?
-    private let client: EventLoopPromise<Channel>
+    private let client: EventLoopPromise<any Channel>
     private let mode: Mode
 
-    enum Mode {
+    enum Mode: Sendable {
       case regular
       case closeOnAccept
     }
@@ -86,7 +86,7 @@ extension ConnectionTest {
       self.client.futureResult.whenSuccess { $0.close(mode: .all, promise: nil) }
     }
 
-    var acceptedChannel: Channel {
+    var acceptedChannel: any Channel {
       get throws {
         try self.client.futureResult.wait()
       }
@@ -95,15 +95,17 @@ extension ConnectionTest {
     func bind() async throws -> GRPCHTTP2Core.SocketAddress {
       precondition(self.listener == nil, "\(#function) must only be called once")
 
-      let hasAcceptedChannel = try await self.eventLoop.submit {
-        NIOLoopBoundBox(false, eventLoop: self.eventLoop)
+      let hasAcceptedChannel = try await self.eventLoop.submit { [loop = self.eventLoop] in
+        NIOLoopBoundBox(false, eventLoop: loop)
       }.get()
 
-      let bootstrap = ServerBootstrap(group: self.eventLoop).childChannelInitializer { channel in
+      let bootstrap = ServerBootstrap(
+        group: self.eventLoop
+      ).childChannelInitializer { [mode = self.mode, client = self.client] channel in
         precondition(!hasAcceptedChannel.value, "already accepted a channel")
         hasAcceptedChannel.value = true
 
-        switch self.mode {
+        switch mode {
         case .closeOnAccept:
           return channel.close()
 
@@ -128,7 +130,7 @@ extension ConnectionTest {
 
             try sync.addHandler(h2)
             try sync.addHandler(mux)
-            try sync.addHandlers(SucceedOnSettingsAck(promise: self.client))
+            try sync.addHandlers(SucceedOnSettingsAck(promise: client))
           }
         }
       }
@@ -147,9 +149,9 @@ extension ConnectionTest {
     typealias InboundIn = HTTP2Frame
     typealias InboundOut = HTTP2Frame
 
-    private let promise: EventLoopPromise<Channel>
+    private let promise: EventLoopPromise<any Channel>
 
-    init(promise: EventLoopPromise<Channel>) {
+    init(promise: EventLoopPromise<any Channel>) {
       self.promise = promise
     }
 

+ 4 - 4
Tests/GRPCHTTP2CoreTests/Client/Connection/Utilities/NameResolvers.swift

@@ -44,8 +44,8 @@ extension NameResolver {
 }
 
 @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
-struct ConstantAsyncSequence<Element>: AsyncSequence {
-  private let result: Result<Element, Error>
+struct ConstantAsyncSequence<Element: Sendable>: AsyncSequence, Sendable {
+  private let result: Result<Element, any Error>
 
   init(element: Element) {
     self.result = .success(element)
@@ -60,9 +60,9 @@ struct ConstantAsyncSequence<Element>: AsyncSequence {
   }
 
   struct AsyncIterator: AsyncIteratorProtocol {
-    private let result: Result<Element, Error>
+    private let result: Result<Element, any Error>
 
-    fileprivate init(result: Result<Element, Error>) {
+    fileprivate init(result: Result<Element, any Error>) {
       self.result = result
     }
 

+ 3 - 3
Tests/GRPCHTTP2CoreTests/Client/Connection/Utilities/TestServer.swift

@@ -29,7 +29,7 @@ final class TestServer: Sendable {
   private typealias Stream = NIOAsyncChannel<RPCRequestPart, RPCResponsePart>
   private typealias Multiplexer = NIOHTTP2AsyncSequence<Stream>
 
-  private let connected: NIOLockedValueBox<[Channel]>
+  private let connected: NIOLockedValueBox<[any Channel]>
 
   typealias Inbound = NIOAsyncChannelInboundStream<RPCRequestPart>
   typealias Outbound = NIOAsyncChannelOutboundWriter<RPCResponsePart>
@@ -47,7 +47,7 @@ final class TestServer: Sendable {
     case uds(String)
   }
 
-  var clients: [Channel] {
+  var clients: [any Channel] {
     return self.connected.withLockedValue { $0 }
   }
 
@@ -55,7 +55,7 @@ final class TestServer: Sendable {
     precondition(self.server.withLockedValue { $0 } == nil)
 
     @Sendable
-    func configure(_ channel: Channel) -> EventLoopFuture<Multiplexer> {
+    func configure(_ channel: any Channel) -> EventLoopFuture<Multiplexer> {
       self.connected.withLockedValue {
         $0.append(channel)
       }

+ 0 - 5
Tests/GRPCHTTP2CoreTests/GRPCStreamStateMachineTests.swift

@@ -2886,10 +2886,5 @@ extension GRPCStreamStateMachine.OnNextOutboundFrame {
   }
 }
 
-#if compiler(>=6.0)
-@available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
-extension GRPCStreamStateMachine.OnNextOutboundFrame: @retroactive Equatable {}
-#else
 @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
 extension GRPCStreamStateMachine.OnNextOutboundFrame: Equatable {}
-#endif

+ 17 - 17
Tests/GRPCHTTP2CoreTests/Internal/TimerTests.swift

@@ -15,32 +15,33 @@
  */
 
 import Atomics
+import GRPCCore
+import GRPCHTTP2Core
 import NIOEmbedded
 import XCTest
 
-@testable import GRPCHTTP2Core
-
 internal final class TimerTests: XCTestCase {
   func testScheduleOneOffTimer() {
     let loop = EmbeddedEventLoop()
     defer { try! loop.close() }
 
-    var value = 0
-
+    let value = LockedValueBox(0)
     var timer = Timer(delay: .seconds(1), repeat: false)
     timer.schedule(on: loop) {
-      XCTAssertEqual(value, 0)
-      value += 1
+      value.withLockedValue {
+        XCTAssertEqual($0, 0)
+        $0 += 1
+      }
     }
 
     loop.advanceTime(by: .milliseconds(999))
-    XCTAssertEqual(value, 0)
+    XCTAssertEqual(value.withLockedValue { $0 }, 0)
     loop.advanceTime(by: .milliseconds(1))
-    XCTAssertEqual(value, 1)
+    XCTAssertEqual(value.withLockedValue { $0 }, 1)
 
     // Run again to make sure the task wasn't repeated.
     loop.advanceTime(by: .seconds(1))
-    XCTAssertEqual(value, 1)
+    XCTAssertEqual(value.withLockedValue { $0 }, 1)
   }
 
   func testCancelOneOffTimer() {
@@ -61,26 +62,25 @@ internal final class TimerTests: XCTestCase {
     let loop = EmbeddedEventLoop()
     defer { try! loop.close() }
 
-    var values = [Int]()
-
+    let values = LockedValueBox([Int]())
     var timer = Timer(delay: .seconds(1), repeat: true)
     timer.schedule(on: loop) {
-      values.append(values.count)
+      values.withLockedValue { $0.append($0.count) }
     }
 
     loop.advanceTime(by: .milliseconds(999))
-    XCTAssertEqual(values, [])
+    XCTAssertEqual(values.withLockedValue { $0 }, [])
     loop.advanceTime(by: .milliseconds(1))
-    XCTAssertEqual(values, [0])
+    XCTAssertEqual(values.withLockedValue { $0 }, [0])
 
     loop.advanceTime(by: .seconds(1))
-    XCTAssertEqual(values, [0, 1])
+    XCTAssertEqual(values.withLockedValue { $0 }, [0, 1])
     loop.advanceTime(by: .seconds(1))
-    XCTAssertEqual(values, [0, 1, 2])
+    XCTAssertEqual(values.withLockedValue { $0 }, [0, 1, 2])
 
     timer.cancel()
     loop.advanceTime(by: .seconds(1))
-    XCTAssertEqual(values, [0, 1, 2])
+    XCTAssertEqual(values.withLockedValue { $0 }, [0, 1, 2])
   }
 
   func testCancelRepeatedTimer() {

+ 1 - 1
Tests/GRPCHTTP2TransportTests/HTTP2TransportTests.swift

@@ -135,7 +135,7 @@ final class HTTP2TransportTests: XCTestCase {
   }
 
   private func runServer(
-    in group: inout ThrowingTaskGroup<Void, Error>,
+    in group: inout ThrowingTaskGroup<Void, any Error>,
     kind: Transport.Kind,
     enableControlService: Bool,
     compression: CompressionAlgorithmSet

+ 1 - 1
Tests/GRPCHTTP2TransportTests/Test Utilities/HTTP2StatusCodeServer.swift

@@ -24,7 +24,7 @@ import NIOPosix
 /// then closing. Each stream will be closed with the ":status" set to the value of the
 /// "response-status" header field in the request headers.
 @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
-final class HTTP2StatusCodeServer {
+final class HTTP2StatusCodeServer: Sendable {
   private let address: EventLoopPromise<GRPCHTTP2Core.SocketAddress.IPv4>
   private let eventLoopGroup: MultiThreadedEventLoopGroup