From 25e9d90fc52de32ef519ebb9e59df18733cbfaf9 Mon Sep 17 00:00:00 2001 From: Mahdi Bahrami Date: Thu, 6 Jul 2023 10:42:24 +0330 Subject: [PATCH 01/16] more @Sendable/@preconcurrency --- .../OpenAPIRuntime/Interface/ClientTransport.swift | 3 ++- .../OpenAPIRuntime/Interface/ServerTransport.swift | 8 ++++---- .../OpenAPIRuntime/Interface/UniversalClient.swift | 8 +++++--- .../OpenAPIRuntime/Interface/UniversalServer.swift | 11 +++++++---- 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/Sources/OpenAPIRuntime/Interface/ClientTransport.swift b/Sources/OpenAPIRuntime/Interface/ClientTransport.swift index 26e105e3..16ab1d3f 100644 --- a/Sources/OpenAPIRuntime/Interface/ClientTransport.swift +++ b/Sources/OpenAPIRuntime/Interface/ClientTransport.swift @@ -229,10 +229,11 @@ public protocol ClientMiddleware: Sendable { /// - operationID: The identifier of the OpenAPI operation. /// - next: A closure that calls the next middleware, or the transport. /// - Returns: An HTTP response. + @preconcurrency func intercept( _ request: Request, baseURL: URL, operationID: String, - next: (Request, URL) async throws -> Response + next: @Sendable (Request, URL) async throws -> Response ) async throws -> Response } diff --git a/Sources/OpenAPIRuntime/Interface/ServerTransport.swift b/Sources/OpenAPIRuntime/Interface/ServerTransport.swift index c7660e1c..0200a931 100644 --- a/Sources/OpenAPIRuntime/Interface/ServerTransport.swift +++ b/Sources/OpenAPIRuntime/Interface/ServerTransport.swift @@ -111,10 +111,9 @@ public protocol ServerTransport { /// - path: The URL path components, for example `["pets", ":petId"]`. /// - queryItemNames: The names of query items to be extracted /// from the request URL that matches the provided HTTP operation. + @preconcurrency func register( - _ handler: @Sendable @escaping ( - Request, ServerRequestMetadata - ) async throws -> Response, + _ handler: @Sendable @escaping (Request, ServerRequestMetadata) async throws -> Response, method: HTTPMethod, path: [RouterPathComponent], queryItemNames: Set @@ -215,10 +214,11 @@ public protocol ServerMiddleware: Sendable { /// - operationID: The identifier of the OpenAPI operation. /// - next: A closure that calls the next middleware, or the transport. /// - Returns: An HTTP response. + @preconcurrency func intercept( _ request: Request, metadata: ServerRequestMetadata, operationID: String, - next: (Request, ServerRequestMetadata) async throws -> Response + next: @Sendable (Request, ServerRequestMetadata) async throws -> Response ) async throws -> Response } diff --git a/Sources/OpenAPIRuntime/Interface/UniversalClient.swift b/Sources/OpenAPIRuntime/Interface/UniversalClient.swift index 785f9b68..15960598 100644 --- a/Sources/OpenAPIRuntime/Interface/UniversalClient.swift +++ b/Sources/OpenAPIRuntime/Interface/UniversalClient.swift @@ -83,12 +83,14 @@ public struct UniversalClient: Sendable { /// - serializer: Creates an HTTP request from the provided Input value. /// - deserializer: Creates an Output value from the provided HTTP response. /// - Returns: The Output value produced by `deserializer`. + @preconcurrency public func send( input: OperationInput, forOperation operationID: String, - serializer: (OperationInput) throws -> Request, - deserializer: (Response) throws -> OperationOutput + serializer: @Sendable (OperationInput) throws -> Request, + deserializer: @Sendable (Response) throws -> OperationOutput ) async throws -> OperationOutput { + @Sendable func wrappingErrors( work: () async throws -> R, mapError: (Error) -> Error @@ -121,7 +123,7 @@ public struct UniversalClient: Sendable { makeError(error: error) } let response: Response = try await wrappingErrors { - var next: (Request, URL) async throws -> Response = { (_request, _url) in + var next: @Sendable (Request, URL) async throws -> Response = { (_request, _url) in try await wrappingErrors { try await transport.send( _request, diff --git a/Sources/OpenAPIRuntime/Interface/UniversalServer.swift b/Sources/OpenAPIRuntime/Interface/UniversalServer.swift index 2f90f508..c6175549 100644 --- a/Sources/OpenAPIRuntime/Interface/UniversalServer.swift +++ b/Sources/OpenAPIRuntime/Interface/UniversalServer.swift @@ -84,14 +84,16 @@ public struct UniversalServer: Sendable { /// - deserializer: Creates an Input value from the provided HTTP request. /// - serializer: Creates an HTTP response from the provided Output value. /// - Returns: The HTTP response produced by `serializer`. + @preconcurrency public func handle( request: Request, with metadata: ServerRequestMetadata, forOperation operationID: String, - using handlerMethod: @escaping (APIHandler) -> ((OperationInput) async throws -> OperationOutput), - deserializer: @escaping (Request, ServerRequestMetadata) throws -> OperationInput, - serializer: @escaping (OperationOutput, Request) throws -> Response + using handlerMethod: @Sendable @escaping (APIHandler) -> ((OperationInput) async throws -> OperationOutput), + deserializer: @Sendable @escaping (Request, ServerRequestMetadata) throws -> OperationInput, + serializer: @Sendable @escaping (OperationOutput, Request) throws -> Response ) async throws -> Response { + @Sendable func wrappingErrors( work: () async throws -> R, mapError: (Error) -> Error @@ -102,6 +104,7 @@ public struct UniversalServer: Sendable { throw mapError(error) } } + @Sendable func makeError( input: OperationInput? = nil, output: OperationOutput? = nil, @@ -116,7 +119,7 @@ public struct UniversalServer: Sendable { underlyingError: error ) } - var next: (Request, ServerRequestMetadata) async throws -> Response = { _request, _metadata in + var next: @Sendable (Request, ServerRequestMetadata) async throws -> Response = { _request, _metadata in let input: OperationInput = try await wrappingErrors { try deserializer(_request, _metadata) } mapError: { error in From 7b5ce9507501d97f6cef51e9ee24929d3de1705d Mon Sep 17 00:00:00 2001 From: Mahdi Bahrami Date: Tue, 11 Jul 2023 16:07:39 +0330 Subject: [PATCH 02/16] remove @preconcurrency attrs of funcs --- Sources/OpenAPIRuntime/Interface/ClientTransport.swift | 1 - Sources/OpenAPIRuntime/Interface/ServerTransport.swift | 2 -- Sources/OpenAPIRuntime/Interface/UniversalClient.swift | 1 - Sources/OpenAPIRuntime/Interface/UniversalServer.swift | 1 - 4 files changed, 5 deletions(-) diff --git a/Sources/OpenAPIRuntime/Interface/ClientTransport.swift b/Sources/OpenAPIRuntime/Interface/ClientTransport.swift index 16ab1d3f..1bbb7a06 100644 --- a/Sources/OpenAPIRuntime/Interface/ClientTransport.swift +++ b/Sources/OpenAPIRuntime/Interface/ClientTransport.swift @@ -229,7 +229,6 @@ public protocol ClientMiddleware: Sendable { /// - operationID: The identifier of the OpenAPI operation. /// - next: A closure that calls the next middleware, or the transport. /// - Returns: An HTTP response. - @preconcurrency func intercept( _ request: Request, baseURL: URL, diff --git a/Sources/OpenAPIRuntime/Interface/ServerTransport.swift b/Sources/OpenAPIRuntime/Interface/ServerTransport.swift index 0200a931..11774140 100644 --- a/Sources/OpenAPIRuntime/Interface/ServerTransport.swift +++ b/Sources/OpenAPIRuntime/Interface/ServerTransport.swift @@ -111,7 +111,6 @@ public protocol ServerTransport { /// - path: The URL path components, for example `["pets", ":petId"]`. /// - queryItemNames: The names of query items to be extracted /// from the request URL that matches the provided HTTP operation. - @preconcurrency func register( _ handler: @Sendable @escaping (Request, ServerRequestMetadata) async throws -> Response, method: HTTPMethod, @@ -214,7 +213,6 @@ public protocol ServerMiddleware: Sendable { /// - operationID: The identifier of the OpenAPI operation. /// - next: A closure that calls the next middleware, or the transport. /// - Returns: An HTTP response. - @preconcurrency func intercept( _ request: Request, metadata: ServerRequestMetadata, diff --git a/Sources/OpenAPIRuntime/Interface/UniversalClient.swift b/Sources/OpenAPIRuntime/Interface/UniversalClient.swift index 15960598..2baf9bed 100644 --- a/Sources/OpenAPIRuntime/Interface/UniversalClient.swift +++ b/Sources/OpenAPIRuntime/Interface/UniversalClient.swift @@ -83,7 +83,6 @@ public struct UniversalClient: Sendable { /// - serializer: Creates an HTTP request from the provided Input value. /// - deserializer: Creates an Output value from the provided HTTP response. /// - Returns: The Output value produced by `deserializer`. - @preconcurrency public func send( input: OperationInput, forOperation operationID: String, diff --git a/Sources/OpenAPIRuntime/Interface/UniversalServer.swift b/Sources/OpenAPIRuntime/Interface/UniversalServer.swift index c6175549..7392b1ef 100644 --- a/Sources/OpenAPIRuntime/Interface/UniversalServer.swift +++ b/Sources/OpenAPIRuntime/Interface/UniversalServer.swift @@ -84,7 +84,6 @@ public struct UniversalServer: Sendable { /// - deserializer: Creates an Input value from the provided HTTP request. /// - serializer: Creates an HTTP response from the provided Output value. /// - Returns: The HTTP response produced by `serializer`. - @preconcurrency public func handle( request: Request, with metadata: ServerRequestMetadata, From 7d3f4fba1653d8fbe055391df779d78b3f9b9a6a Mon Sep 17 00:00:00 2001 From: Mahdi Bahrami Date: Tue, 11 Jul 2023 16:43:17 +0330 Subject: [PATCH 03/16] full strict-concurrency support --- .../OpenAPIRuntime/Base/OpenAPIValue.swift | 14 ++--- .../OpenAPIRuntime/Errors/ClientError.swift | 4 +- .../OpenAPIRuntime/Errors/ServerError.swift | 8 +-- .../Interface/CurrencyTypes.swift | 58 ++++++++++++------- .../Interface/UniversalClient.swift | 2 +- .../Interface/UniversalServer.swift | 2 +- docker/Dockerfile | 2 +- 7 files changed, 54 insertions(+), 36 deletions(-) diff --git a/Sources/OpenAPIRuntime/Base/OpenAPIValue.swift b/Sources/OpenAPIRuntime/Base/OpenAPIValue.swift index ab6a9f65..55feaf0f 100644 --- a/Sources/OpenAPIRuntime/Base/OpenAPIValue.swift +++ b/Sources/OpenAPIRuntime/Base/OpenAPIValue.swift @@ -52,7 +52,7 @@ public struct OpenAPIValueContainer: Codable, Equatable, Hashable, Sendable { /// - Parameter unvalidatedValue: A value of a JSON-compatible type, /// such as `String`, `[Any]`, and `[String: Any]`. /// - Throws: When the value is not supported. - public init(unvalidatedValue: Any? = nil) throws { + public init(unvalidatedValue: (any Sendable)? = nil) throws { try self.init(validatedValue: Self.tryCast(unvalidatedValue)) } @@ -62,14 +62,14 @@ public struct OpenAPIValueContainer: Codable, Equatable, Hashable, Sendable { /// - Parameter value: An untyped value. /// - Returns: A cast value if supported. /// - Throws: When the value is not supported. - static func tryCast(_ value: Any?) throws -> Sendable? { + static func tryCast(_ value: (any Sendable)?) throws -> Sendable? { guard let value = value else { return nil } - if let array = value as? [Any?] { + if let array = value as? [(any Sendable)?] { return try array.map(tryCast(_:)) } - if let dictionary = value as? [String: Any?] { + if let dictionary = value as? [String: (any Sendable)?] { return try dictionary.mapValues(tryCast(_:)) } if let value = tryCastPrimitiveType(value) { @@ -87,7 +87,7 @@ public struct OpenAPIValueContainer: Codable, Equatable, Hashable, Sendable { /// Returns the specified value cast to a supported primitive type. /// - Parameter value: An untyped value. /// - Returns: A cast value if supported, nil otherwise. - static func tryCastPrimitiveType(_ value: Any) -> Sendable? { + static func tryCastPrimitiveType(_ value: any Sendable) -> (any Sendable)? { switch value { case is String, is Int, is Bool, is Double: return value @@ -327,7 +327,7 @@ public struct OpenAPIObjectContainer: Codable, Equatable, Hashable, Sendable { public func encode(to encoder: Encoder) throws { var container = encoder.singleValueContainer() - try container.encode(value.mapValues(OpenAPIValueContainer.init)) + try container.encode(value.mapValues(OpenAPIValueContainer.init(unvalidatedValue:))) } // MARK: Equatable @@ -430,7 +430,7 @@ public struct OpenAPIArrayContainer: Codable, Equatable, Hashable, Sendable { public func encode(to encoder: Encoder) throws { var container = encoder.singleValueContainer() - try container.encode(value.map(OpenAPIValueContainer.init)) + try container.encode(value.map(OpenAPIValueContainer.init(unvalidatedValue:))) } // MARK: Equatable diff --git a/Sources/OpenAPIRuntime/Errors/ClientError.swift b/Sources/OpenAPIRuntime/Errors/ClientError.swift index 472f854a..bad499ec 100644 --- a/Sources/OpenAPIRuntime/Errors/ClientError.swift +++ b/Sources/OpenAPIRuntime/Errors/ClientError.swift @@ -24,7 +24,7 @@ public struct ClientError: Error { public var operationID: String /// The operation-specific Input value. - public var operationInput: Any + public var operationInput: any Sendable /// The HTTP request created during the operation. /// @@ -56,7 +56,7 @@ public struct ClientError: Error { /// - underlyingError: The underlying error that caused the operation to fail. public init( operationID: String, - operationInput: Any, + operationInput: any Sendable, request: Request? = nil, baseURL: URL? = nil, response: Response? = nil, diff --git a/Sources/OpenAPIRuntime/Errors/ServerError.swift b/Sources/OpenAPIRuntime/Errors/ServerError.swift index 5f637b44..9fe2a94d 100644 --- a/Sources/OpenAPIRuntime/Errors/ServerError.swift +++ b/Sources/OpenAPIRuntime/Errors/ServerError.swift @@ -27,12 +27,12 @@ public struct ServerError: Error { /// Operation-specific Input value. /// /// Is nil if error was thrown during request -> Input conversion. - public var operationInput: Any? + public var operationInput: (any Sendable)? /// Operation-specific Output value. /// /// Is nil if error was thrown before/during Output -> response conversion. - public var operationOutput: Any? + public var operationOutput: (any Sendable)? /// The underlying error that caused the operation to fail. public var underlyingError: Error @@ -50,8 +50,8 @@ public struct ServerError: Error { operationID: String, request: Request, requestMetadata: ServerRequestMetadata, - operationInput: Any? = nil, - operationOutput: Any? = nil, + operationInput: (any Sendable)? = nil, + operationOutput: (any Sendable)? = nil, underlyingError: Error ) { self.operationID = operationID diff --git a/Sources/OpenAPIRuntime/Interface/CurrencyTypes.swift b/Sources/OpenAPIRuntime/Interface/CurrencyTypes.swift index 09bab14c..8786b0c6 100644 --- a/Sources/OpenAPIRuntime/Interface/CurrencyTypes.swift +++ b/Sources/OpenAPIRuntime/Interface/CurrencyTypes.swift @@ -17,6 +17,41 @@ import Foundation @preconcurrency import Foundation #endif +/// A protected-by-locks storage for ``redactedHeaderFields``. +private class RedactedHeadersStorage: @unchecked Sendable { + /// The underlying storage of ``redactedHeaderFields``, + /// protected by a lock. + private var _locked_redactedHeaderFields: Set = HeaderField.defaultRedactedHeaderFields + + /// The header fields to be redacted. + var redactedHeaderFields: Set { + get { + lock.lock() + defer { + lock.unlock() + } + return _locked_redactedHeaderFields + } + set { + lock.lock() + defer { + lock.unlock() + } + _locked_redactedHeaderFields = newValue + } + } + + /// The lock used for protecting access to `_locked_redactedHeaderFields`. + private let lock: NSLock = { + let lock = NSLock() + lock.name = "com.apple.swift-openapi-runtime.lock.redactedHeaderFields" + return lock + }() + + init() { } +} + + /// A header field used in an HTTP request or response. public struct HeaderField: Equatable, Hashable, Sendable { @@ -47,20 +82,12 @@ extension HeaderField { /// Use this to avoid leaking sensitive tokens into application logs. public static var redactedHeaderFields: Set { set { - _lock_redactedHeaderFields.lock() - defer { - _lock_redactedHeaderFields.unlock() - } // Save lowercased versions of the header field names to make // membership checking O(1). - _locked_redactedHeaderFields = Set(newValue.map { $0.lowercased() }) + redactedHeadersStorage.redactedHeaderFields = Set(newValue.map { $0.lowercased() }) } get { - _lock_redactedHeaderFields.lock() - defer { - _lock_redactedHeaderFields.unlock() - } - return _locked_redactedHeaderFields + return redactedHeadersStorage.redactedHeaderFields } } @@ -71,16 +98,7 @@ extension HeaderField { "set-cookie", ] - /// The lock used for protecting access to `_locked_redactedHeaderFields`. - private static let _lock_redactedHeaderFields: NSLock = { - let lock = NSLock() - lock.name = "com.apple.swift-openapi-runtime.lock.redactedHeaderFields" - return lock - }() - - /// The underlying storage of ``HeaderField/redactedHeaderFields``, - /// protected by a lock. - private static var _locked_redactedHeaderFields: Set = defaultRedactedHeaderFields + private static let redactedHeadersStorage = RedactedHeadersStorage() } /// Describes the HTTP method used in an OpenAPI operation. diff --git a/Sources/OpenAPIRuntime/Interface/UniversalClient.swift b/Sources/OpenAPIRuntime/Interface/UniversalClient.swift index 2baf9bed..e16646fb 100644 --- a/Sources/OpenAPIRuntime/Interface/UniversalClient.swift +++ b/Sources/OpenAPIRuntime/Interface/UniversalClient.swift @@ -88,7 +88,7 @@ public struct UniversalClient: Sendable { forOperation operationID: String, serializer: @Sendable (OperationInput) throws -> Request, deserializer: @Sendable (Response) throws -> OperationOutput - ) async throws -> OperationOutput { + ) async throws -> OperationOutput where OperationInput: Sendable, OperationOutput: Sendable { @Sendable func wrappingErrors( work: () async throws -> R, diff --git a/Sources/OpenAPIRuntime/Interface/UniversalServer.swift b/Sources/OpenAPIRuntime/Interface/UniversalServer.swift index 7392b1ef..ed10e614 100644 --- a/Sources/OpenAPIRuntime/Interface/UniversalServer.swift +++ b/Sources/OpenAPIRuntime/Interface/UniversalServer.swift @@ -91,7 +91,7 @@ public struct UniversalServer: Sendable { using handlerMethod: @Sendable @escaping (APIHandler) -> ((OperationInput) async throws -> OperationOutput), deserializer: @Sendable @escaping (Request, ServerRequestMetadata) throws -> OperationInput, serializer: @Sendable @escaping (OperationOutput, Request) throws -> Response - ) async throws -> Response { + ) async throws -> Response where OperationInput: Sendable, OperationOutput: Sendable { @Sendable func wrappingErrors( work: () async throws -> R, diff --git a/docker/Dockerfile b/docker/Dockerfile index 33f860d9..89d4c9e6 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -19,7 +19,7 @@ RUN echo 'export PATH="$HOME/.tools:$PATH"' >> $HOME/.profile # swift-format ARG swiftformat_version=508.0.0 RUN git clone --branch $swiftformat_version --depth 1 https://github.com/apple/swift-format $HOME/.tools/swift-format-source -RUN cd $HOME/.tools/swift-format-source && swift build -c release +RUN cd $HOME/.tools/swift-format-source && swift build -c release -Xswiftc -strict-concurrency=complete RUN ln -s $HOME/.tools/swift-format-source/.build/release/swift-format $HOME/.tools/swift-format # jq From 263731a00e4ab36bb016686f056b9e61d1508ece Mon Sep 17 00:00:00 2001 From: Mahdi Bahrami Date: Tue, 11 Jul 2023 16:49:19 +0330 Subject: [PATCH 04/16] move strict-concurrency flag to script --- docker/Dockerfile | 2 +- scripts/run-integration-test.sh | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 89d4c9e6..33f860d9 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -19,7 +19,7 @@ RUN echo 'export PATH="$HOME/.tools:$PATH"' >> $HOME/.profile # swift-format ARG swiftformat_version=508.0.0 RUN git clone --branch $swiftformat_version --depth 1 https://github.com/apple/swift-format $HOME/.tools/swift-format-source -RUN cd $HOME/.tools/swift-format-source && swift build -c release -Xswiftc -strict-concurrency=complete +RUN cd $HOME/.tools/swift-format-source && swift build -c release RUN ln -s $HOME/.tools/swift-format-source/.build/release/swift-format $HOME/.tools/swift-format # jq diff --git a/scripts/run-integration-test.sh b/scripts/run-integration-test.sh index f9928287..7d9bc034 100644 --- a/scripts/run-integration-test.sh +++ b/scripts/run-integration-test.sh @@ -43,6 +43,7 @@ swift package --package-path "${INTEGRATION_TEST_PACKAGE_PATH}" \ edit "${PACKAGE_NAME}" --path "${PACKAGE_PATH}" log "Building integration test package: ${INTEGRATION_TEST_PACKAGE_PATH}" -swift build --package-path "${INTEGRATION_TEST_PACKAGE_PATH}" +swift build --package-path "${INTEGRATION_TEST_PACKAGE_PATH}" \ + -Xswiftc -strict-concurrency=complete log "✅ Successfully built integration test package." From fe4b6d29d715a3e6e1cf8e08a3206e02aba499fa Mon Sep 17 00:00:00 2001 From: Mahdi Bahrami Date: Tue, 11 Jul 2023 16:57:00 +0330 Subject: [PATCH 05/16] remove the strict-concurrency flag for now --- scripts/run-integration-test.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts/run-integration-test.sh b/scripts/run-integration-test.sh index 7d9bc034..f9928287 100644 --- a/scripts/run-integration-test.sh +++ b/scripts/run-integration-test.sh @@ -43,7 +43,6 @@ swift package --package-path "${INTEGRATION_TEST_PACKAGE_PATH}" \ edit "${PACKAGE_NAME}" --path "${PACKAGE_PATH}" log "Building integration test package: ${INTEGRATION_TEST_PACKAGE_PATH}" -swift build --package-path "${INTEGRATION_TEST_PACKAGE_PATH}" \ - -Xswiftc -strict-concurrency=complete +swift build --package-path "${INTEGRATION_TEST_PACKAGE_PATH}" log "✅ Successfully built integration test package." From df8a65e9ce9f3f58827f18f0f3d81446cf916f8d Mon Sep 17 00:00:00 2001 From: Mahdi Bahrami Date: Tue, 11 Jul 2023 17:12:43 +0330 Subject: [PATCH 06/16] soundness --- Sources/OpenAPIRuntime/Interface/CurrencyTypes.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/OpenAPIRuntime/Interface/CurrencyTypes.swift b/Sources/OpenAPIRuntime/Interface/CurrencyTypes.swift index 8786b0c6..e9adc44e 100644 --- a/Sources/OpenAPIRuntime/Interface/CurrencyTypes.swift +++ b/Sources/OpenAPIRuntime/Interface/CurrencyTypes.swift @@ -48,7 +48,7 @@ private class RedactedHeadersStorage: @unchecked Sendable { return lock }() - init() { } + init() {} } From 5583f8bd95390c19024479d7d2683ba381683b39 Mon Sep 17 00:00:00 2001 From: Mahdi Bahrami Date: Wed, 12 Jul 2023 01:38:06 +0330 Subject: [PATCH 07/16] add strict-concurrency to docker-compose --- docker/docker-compose.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml index be08dd94..6f37c980 100644 --- a/docker/docker-compose.yaml +++ b/docker/docker-compose.yaml @@ -30,7 +30,7 @@ services: test: <<: *common - command: /bin/bash -xcl "swift $${SWIFT_TEST_VERB-test} $${WARN_AS_ERROR_ARG-} $${SANITIZER_ARG-} $${IMPORT_CHECK_ARG-}" + command: /bin/bash -xcl "swift $${SWIFT_TEST_VERB-test} $${WARN_AS_ERROR_ARG-} $${SANITIZER_ARG-} $${IMPORT_CHECK_ARG-} -Xswiftc -strict-concurrency=complete" shell: <<: *common From a7a4ff9fe8ee0386f3d672bdc3a6b693e3ccd171 Mon Sep 17 00:00:00 2001 From: Mahdi Bahrami Date: Wed, 12 Jul 2023 01:42:41 +0330 Subject: [PATCH 08/16] soundness --- Sources/OpenAPIRuntime/Interface/CurrencyTypes.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Sources/OpenAPIRuntime/Interface/CurrencyTypes.swift b/Sources/OpenAPIRuntime/Interface/CurrencyTypes.swift index e9adc44e..77209f60 100644 --- a/Sources/OpenAPIRuntime/Interface/CurrencyTypes.swift +++ b/Sources/OpenAPIRuntime/Interface/CurrencyTypes.swift @@ -51,7 +51,6 @@ private class RedactedHeadersStorage: @unchecked Sendable { init() {} } - /// A header field used in an HTTP request or response. public struct HeaderField: Equatable, Hashable, Sendable { From 8c10e2c7b45355ee17d43a40c853b1bb4ac3d120 Mon Sep 17 00:00:00 2001 From: Mahdi Bahrami Date: Wed, 12 Jul 2023 02:05:39 +0330 Subject: [PATCH 09/16] try to resolve Sendable failures --- Sources/OpenAPIRuntime/Errors/ClientError.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Sources/OpenAPIRuntime/Errors/ClientError.swift b/Sources/OpenAPIRuntime/Errors/ClientError.swift index bad499ec..bdb56114 100644 --- a/Sources/OpenAPIRuntime/Errors/ClientError.swift +++ b/Sources/OpenAPIRuntime/Errors/ClientError.swift @@ -11,7 +11,11 @@ // SPDX-License-Identifier: Apache-2.0 // //===----------------------------------------------------------------------===// +#if canImport(Darwin) import Foundation +#else +@preconcurrency import Foundation +#endif /// An error thrown by a client performing an OpenAPI operation. /// From 30b9cc3003092bd4977bf89df86985af23b75f5b Mon Sep 17 00:00:00 2001 From: Mahdi Bahrami Date: Wed, 12 Jul 2023 14:39:46 +0330 Subject: [PATCH 10/16] Update Sources/OpenAPIRuntime/Interface/CurrencyTypes.swift Co-authored-by: Si Beaumont --- Sources/OpenAPIRuntime/Interface/CurrencyTypes.swift | 2 -- 1 file changed, 2 deletions(-) diff --git a/Sources/OpenAPIRuntime/Interface/CurrencyTypes.swift b/Sources/OpenAPIRuntime/Interface/CurrencyTypes.swift index 77209f60..218e90ee 100644 --- a/Sources/OpenAPIRuntime/Interface/CurrencyTypes.swift +++ b/Sources/OpenAPIRuntime/Interface/CurrencyTypes.swift @@ -47,8 +47,6 @@ private class RedactedHeadersStorage: @unchecked Sendable { lock.name = "com.apple.swift-openapi-runtime.lock.redactedHeaderFields" return lock }() - - init() {} } /// A header field used in an HTTP request or response. From 5fb3d06cce4fa62dab103fee17c6ab95628138fd Mon Sep 17 00:00:00 2001 From: Mahdi Bahrami Date: Wed, 12 Jul 2023 14:42:41 +0330 Subject: [PATCH 11/16] better strict-concurrency flag --- docker/docker-compose.2204.58.yaml | 1 + docker/docker-compose.2204.59.yaml | 1 + docker/docker-compose.2204.main.yaml | 1 + docker/docker-compose.yaml | 2 +- 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docker/docker-compose.2204.58.yaml b/docker/docker-compose.2204.58.yaml index d003c00f..071d15ba 100644 --- a/docker/docker-compose.2204.58.yaml +++ b/docker/docker-compose.2204.58.yaml @@ -13,6 +13,7 @@ services: environment: - WARN_AS_ERROR_ARG=-Xswiftc -warnings-as-errors - IMPORT_CHECK_ARG=--explicit-target-dependency-import-check error + - STRICT_CONCURRENCY_ARG=-Xswiftc -strict-concurrency=complete shell: image: *image diff --git a/docker/docker-compose.2204.59.yaml b/docker/docker-compose.2204.59.yaml index 36d86acf..5ef2848d 100644 --- a/docker/docker-compose.2204.59.yaml +++ b/docker/docker-compose.2204.59.yaml @@ -12,6 +12,7 @@ services: environment: - WARN_AS_ERROR_ARG=-Xswiftc -warnings-as-errors - IMPORT_CHECK_ARG=--explicit-target-dependency-import-check error + - STRICT_CONCURRENCY_ARG=-Xswiftc -strict-concurrency=complete shell: image: *image diff --git a/docker/docker-compose.2204.main.yaml b/docker/docker-compose.2204.main.yaml index d30087a9..c40ac1ac 100644 --- a/docker/docker-compose.2204.main.yaml +++ b/docker/docker-compose.2204.main.yaml @@ -13,6 +13,7 @@ services: environment: - WARN_AS_ERROR_ARG=-Xswiftc -warnings-as-errors - IMPORT_CHECK_ARG=--explicit-target-dependency-import-check error + - STRICT_CONCURRENCY_ARG=-Xswiftc -strict-concurrency=complete shell: image: *image diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml index 6f37c980..25543b2e 100644 --- a/docker/docker-compose.yaml +++ b/docker/docker-compose.yaml @@ -30,7 +30,7 @@ services: test: <<: *common - command: /bin/bash -xcl "swift $${SWIFT_TEST_VERB-test} $${WARN_AS_ERROR_ARG-} $${SANITIZER_ARG-} $${IMPORT_CHECK_ARG-} -Xswiftc -strict-concurrency=complete" + command: /bin/bash -xcl "swift $${SWIFT_TEST_VERB-test} $${WARN_AS_ERROR_ARG-} $${SANITIZER_ARG-} $${IMPORT_CHECK_ARG-} $${STRICT_CONCURRENCY_ARG-}" shell: <<: *common From a4e6e7263e5c9a6c7e2433182bbfacc11fea9c60 Mon Sep 17 00:00:00 2001 From: Mahdi Bahrami Date: Wed, 12 Jul 2023 16:18:28 +0330 Subject: [PATCH 12/16] @preconcurrency import comments --- Sources/OpenAPIRuntime/Conversion/Converter.swift | 1 + Sources/OpenAPIRuntime/Errors/ClientError.swift | 1 + Sources/OpenAPIRuntime/Interface/CurrencyTypes.swift | 4 ---- Sources/OpenAPIRuntime/Interface/UniversalClient.swift | 1 + 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Sources/OpenAPIRuntime/Conversion/Converter.swift b/Sources/OpenAPIRuntime/Conversion/Converter.swift index 2aac6668..8dc638cb 100644 --- a/Sources/OpenAPIRuntime/Conversion/Converter.swift +++ b/Sources/OpenAPIRuntime/Conversion/Converter.swift @@ -14,6 +14,7 @@ #if canImport(Darwin) import Foundation #else +// `@preconcrrency` is for `JSONDecoder`/`JSONEncoder`. @preconcurrency import Foundation #endif diff --git a/Sources/OpenAPIRuntime/Errors/ClientError.swift b/Sources/OpenAPIRuntime/Errors/ClientError.swift index bdb56114..5d778c74 100644 --- a/Sources/OpenAPIRuntime/Errors/ClientError.swift +++ b/Sources/OpenAPIRuntime/Errors/ClientError.swift @@ -14,6 +14,7 @@ #if canImport(Darwin) import Foundation #else +// `@preconcrrency` is for `URL`. @preconcurrency import Foundation #endif diff --git a/Sources/OpenAPIRuntime/Interface/CurrencyTypes.swift b/Sources/OpenAPIRuntime/Interface/CurrencyTypes.swift index 218e90ee..51d6058a 100644 --- a/Sources/OpenAPIRuntime/Interface/CurrencyTypes.swift +++ b/Sources/OpenAPIRuntime/Interface/CurrencyTypes.swift @@ -11,11 +11,7 @@ // SPDX-License-Identifier: Apache-2.0 // //===----------------------------------------------------------------------===// -#if canImport(Darwin) import Foundation -#else -@preconcurrency import Foundation -#endif /// A protected-by-locks storage for ``redactedHeaderFields``. private class RedactedHeadersStorage: @unchecked Sendable { diff --git a/Sources/OpenAPIRuntime/Interface/UniversalClient.swift b/Sources/OpenAPIRuntime/Interface/UniversalClient.swift index e16646fb..56045d86 100644 --- a/Sources/OpenAPIRuntime/Interface/UniversalClient.swift +++ b/Sources/OpenAPIRuntime/Interface/UniversalClient.swift @@ -14,6 +14,7 @@ #if canImport(Darwin) import Foundation #else +// `@preconcrrency` is for `URL`. @preconcurrency import Foundation #endif From 9bcec07ea239aa326057720c9c4f8b1be7687643 Mon Sep 17 00:00:00 2001 From: Mahdi Bahrami Date: Wed, 12 Jul 2023 16:22:15 +0330 Subject: [PATCH 13/16] add back an @preconcurrency --- Sources/OpenAPIRuntime/Interface/CurrencyTypes.swift | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Sources/OpenAPIRuntime/Interface/CurrencyTypes.swift b/Sources/OpenAPIRuntime/Interface/CurrencyTypes.swift index 51d6058a..94e962c1 100644 --- a/Sources/OpenAPIRuntime/Interface/CurrencyTypes.swift +++ b/Sources/OpenAPIRuntime/Interface/CurrencyTypes.swift @@ -11,7 +11,12 @@ // SPDX-License-Identifier: Apache-2.0 // //===----------------------------------------------------------------------===// +#if canImport(Darwin) import Foundation +#else +// `@preconcrrency` is for `Data`/`URLQueryItem`. +@preconcurrency import Foundation +#endif /// A protected-by-locks storage for ``redactedHeaderFields``. private class RedactedHeadersStorage: @unchecked Sendable { From 0da5e1e171d11df047b9fe17745a90414be99bb6 Mon Sep 17 00:00:00 2001 From: Mahdi Bahrami Date: Wed, 12 Jul 2023 18:30:25 +0330 Subject: [PATCH 14/16] fix usage of wrong OpenAPIValueContainer init --- Sources/OpenAPIRuntime/Base/OpenAPIValue.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/OpenAPIRuntime/Base/OpenAPIValue.swift b/Sources/OpenAPIRuntime/Base/OpenAPIValue.swift index 55feaf0f..0c9cd496 100644 --- a/Sources/OpenAPIRuntime/Base/OpenAPIValue.swift +++ b/Sources/OpenAPIRuntime/Base/OpenAPIValue.swift @@ -327,7 +327,7 @@ public struct OpenAPIObjectContainer: Codable, Equatable, Hashable, Sendable { public func encode(to encoder: Encoder) throws { var container = encoder.singleValueContainer() - try container.encode(value.mapValues(OpenAPIValueContainer.init(unvalidatedValue:))) + try container.encode(value.mapValues(OpenAPIValueContainer.init(validatedValue:))) } // MARK: Equatable @@ -430,7 +430,7 @@ public struct OpenAPIArrayContainer: Codable, Equatable, Hashable, Sendable { public func encode(to encoder: Encoder) throws { var container = encoder.singleValueContainer() - try container.encode(value.map(OpenAPIValueContainer.init(unvalidatedValue:))) + try container.encode(value.map(OpenAPIValueContainer.init(validatedValue:))) } // MARK: Equatable From 2607e3946bafc1873a7773284a59ccceb81d51f0 Mon Sep 17 00:00:00 2001 From: Mahdi Bahrami Date: Thu, 13 Jul 2023 12:43:59 +0330 Subject: [PATCH 15/16] add strict-concurrency flag to Dockerfile --- docker/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 33f860d9..89d4c9e6 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -19,7 +19,7 @@ RUN echo 'export PATH="$HOME/.tools:$PATH"' >> $HOME/.profile # swift-format ARG swiftformat_version=508.0.0 RUN git clone --branch $swiftformat_version --depth 1 https://github.com/apple/swift-format $HOME/.tools/swift-format-source -RUN cd $HOME/.tools/swift-format-source && swift build -c release +RUN cd $HOME/.tools/swift-format-source && swift build -c release -Xswiftc -strict-concurrency=complete RUN ln -s $HOME/.tools/swift-format-source/.build/release/swift-format $HOME/.tools/swift-format # jq From e46927937140874deb818c9a4ffc643ae0f1634c Mon Sep 17 00:00:00 2001 From: Mahdi Bahrami Date: Thu, 13 Jul 2023 13:12:04 +0330 Subject: [PATCH 16/16] move the strict-concurrency flag to the correct place --- docker/Dockerfile | 2 +- scripts/run-integration-test.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 89d4c9e6..33f860d9 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -19,7 +19,7 @@ RUN echo 'export PATH="$HOME/.tools:$PATH"' >> $HOME/.profile # swift-format ARG swiftformat_version=508.0.0 RUN git clone --branch $swiftformat_version --depth 1 https://github.com/apple/swift-format $HOME/.tools/swift-format-source -RUN cd $HOME/.tools/swift-format-source && swift build -c release -Xswiftc -strict-concurrency=complete +RUN cd $HOME/.tools/swift-format-source && swift build -c release RUN ln -s $HOME/.tools/swift-format-source/.build/release/swift-format $HOME/.tools/swift-format # jq diff --git a/scripts/run-integration-test.sh b/scripts/run-integration-test.sh index f9928287..8042f9a8 100644 --- a/scripts/run-integration-test.sh +++ b/scripts/run-integration-test.sh @@ -43,6 +43,6 @@ swift package --package-path "${INTEGRATION_TEST_PACKAGE_PATH}" \ edit "${PACKAGE_NAME}" --path "${PACKAGE_PATH}" log "Building integration test package: ${INTEGRATION_TEST_PACKAGE_PATH}" -swift build --package-path "${INTEGRATION_TEST_PACKAGE_PATH}" +swift build --package-path "${INTEGRATION_TEST_PACKAGE_PATH}" -Xswiftc -strict-concurrency=complete log "✅ Successfully built integration test package."