diff --git a/Sources/Nimble/Adapters/NMBExpectation.swift b/Sources/Nimble/Adapters/NMBExpectation.swift index 6ca25fb7b..be1768d58 100644 --- a/Sources/Nimble/Adapters/NMBExpectation.swift +++ b/Sources/Nimble/Adapters/NMBExpectation.swift @@ -14,13 +14,13 @@ private func from(objcMatcher: NMBMatcher) -> Matcher { // Equivalent to Expectation, but for Nimble's Objective-C interface public final class NMBExpectation: NSObject, Sendable { - internal let _actualBlock: @Sendable () -> sending NSObject? + internal let _actualBlock: @Sendable () -> NSObject? internal let _negative: Bool internal let _file: FileString internal let _line: UInt internal let _timeout: NimbleTimeInterval - @objc public init(actualBlock: @escaping @Sendable () -> sending NSObject?, negative: Bool, file: FileString, line: UInt) { + @objc public init(actualBlock: @escaping @Sendable () -> NSObject?, negative: Bool, file: FileString, line: UInt) { self._actualBlock = actualBlock self._negative = negative self._file = file @@ -28,7 +28,7 @@ public final class NMBExpectation: NSObject, Sendable { self._timeout = .seconds(1) } - private init(actualBlock: @escaping @Sendable () -> sending NSObject?, negative: Bool, file: FileString, line: UInt, timeout: NimbleTimeInterval) { + private init(actualBlock: @escaping @Sendable () -> NSObject?, negative: Bool, file: FileString, line: UInt, timeout: NimbleTimeInterval) { self._actualBlock = actualBlock self._negative = negative self._file = file diff --git a/Sources/Nimble/AsyncExpression.swift b/Sources/Nimble/AsyncExpression.swift index 7eb0d228f..22c366cf2 100644 --- a/Sources/Nimble/AsyncExpression.swift +++ b/Sources/Nimble/AsyncExpression.swift @@ -67,7 +67,7 @@ private final class MemoizedClosure: Sendable { // Memoizes the given closure, only calling the passed // closure once; even if repeat calls to the returned closure private func memoizedClosure( - _ closure: sending @escaping @Sendable () async throws -> T + _ closure: @escaping @Sendable () async throws -> T ) -> @Sendable (Bool) async throws -> T { let memoized = MemoizedClosure(closure) return memoized.callAsFunction(_:) @@ -85,7 +85,7 @@ private func memoizedClosure( /// This provides a common consumable API for matchers to utilize to allow /// Nimble to change internals to how the captured closure is managed. public actor AsyncExpression { - internal let _expression: @Sendable (Bool) async throws -> sending Value? + internal let _expression: @Sendable (Bool) async throws -> Value? internal let _withoutCaching: Bool public let location: SourceLocation public let isClosure: Bool @@ -101,7 +101,7 @@ public actor AsyncExpression { /// requires an explicit closure. This gives Nimble /// flexibility if @autoclosure behavior changes between /// Swift versions. Nimble internals always sets this true. - public init(expression: sending @escaping @Sendable () async throws -> sending Value?, location: SourceLocation, isClosure: Bool = true) { + public init(expression: @escaping @Sendable () async throws -> Value?, location: SourceLocation, isClosure: Bool = true) { self._expression = memoizedClosure(expression) self.location = location self._withoutCaching = false @@ -122,7 +122,7 @@ public actor AsyncExpression { /// requires an explicit closure. This gives Nimble /// flexibility if @autoclosure behavior changes between /// Swift versions. Nimble internals always sets this true. - public init(memoizedExpression: @escaping @Sendable (Bool) async throws -> sending Value?, location: SourceLocation, withoutCaching: Bool, isClosure: Bool = true) { + public init(memoizedExpression: @escaping @Sendable (Bool) async throws -> Value?, location: SourceLocation, withoutCaching: Bool, isClosure: Bool = true) { self._expression = memoizedExpression self.location = location self._withoutCaching = withoutCaching @@ -153,7 +153,7 @@ public actor AsyncExpression { /// /// - Parameter block: The block that can cast the current Expression value to a /// new type. - public func cast(_ block: @escaping @Sendable (Value?) throws -> sending U?) -> AsyncExpression { + public func cast(_ block: @escaping @Sendable (Value?) throws -> U?) -> AsyncExpression { AsyncExpression( expression: ({ try await block(self.evaluate()) }), location: self.location, @@ -161,7 +161,7 @@ public actor AsyncExpression { ) } - public func cast(_ block: @escaping @Sendable (Value?) async throws -> sending U?) -> AsyncExpression { + public func cast(_ block: @escaping @Sendable (Value?) async throws -> U?) -> AsyncExpression { AsyncExpression( expression: ({ try await block(self.evaluate()) }), location: self.location, @@ -169,7 +169,7 @@ public actor AsyncExpression { ) } - public func evaluate() async throws -> sending Value? { + public func evaluate() async throws -> Value? { try await self._expression(_withoutCaching) } diff --git a/Sources/Nimble/DSL+AsyncAwait.swift b/Sources/Nimble/DSL+AsyncAwait.swift index 3fb6e6a15..c7deecc91 100644 --- a/Sources/Nimble/DSL+AsyncAwait.swift +++ b/Sources/Nimble/DSL+AsyncAwait.swift @@ -3,7 +3,7 @@ import Dispatch #endif /// Make an ``AsyncExpectation`` on a given actual value. The value given is lazily evaluated. -public func expect(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, _ expression: @escaping @Sendable () async throws -> sending T?) -> AsyncExpectation { +public func expect(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, _ expression: @escaping @Sendable () async throws -> T?) -> AsyncExpectation { return AsyncExpectation( expression: AsyncExpression( expression: expression, @@ -12,7 +12,7 @@ public func expect(fileID: String = #fileID, file: FileString = #fi } /// Make an ``AsyncExpectation`` on a given actual value. The closure is lazily invoked. -public func expect(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, _ expression: @Sendable () -> (@Sendable () async throws -> sending T)) -> AsyncExpectation { +public func expect(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, _ expression: @Sendable () -> (@Sendable () async throws -> T)) -> AsyncExpectation { return AsyncExpectation( expression: AsyncExpression( expression: expression(), @@ -21,7 +21,7 @@ public func expect(fileID: String = #fileID, file: FileString = #fi } /// Make an ``AsyncExpectation`` on a given actual value. The closure is lazily invoked. -public func expect(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, _ expression: @Sendable () -> (@Sendable () async throws -> sending T?)) -> AsyncExpectation { +public func expect(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, _ expression: @Sendable () -> (@Sendable () async throws -> T?)) -> AsyncExpectation { return AsyncExpectation( expression: AsyncExpression( expression: expression(), @@ -30,7 +30,7 @@ public func expect(fileID: String = #fileID, file: FileString = #fi } /// Make an ``AsyncExpectation`` on a given actual value. The closure is lazily invoked. -public func expect(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, _ expression: @Sendable () -> (@Sendable () async throws -> sending Void)) -> AsyncExpectation { +public func expect(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, _ expression: @Sendable () -> (@Sendable () async throws -> Void)) -> AsyncExpectation { return AsyncExpectation( expression: AsyncExpression( expression: expression(), @@ -40,7 +40,7 @@ public func expect(fileID: String = #fileID, file: FileString = #filePath, line: /// Make an ``AsyncExpectation`` on a given actual value. The value given is lazily evaluated. /// This is provided to avoid confusion between `expect -> SyncExpectation` and `expect -> AsyncExpectation`. -public func expecta(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, _ expression: @autoclosure @escaping @Sendable () async throws -> sending T?) async -> AsyncExpectation { +public func expecta(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, _ expression: @autoclosure @escaping @Sendable () async throws -> T?) async -> AsyncExpectation { return AsyncExpectation( expression: AsyncExpression( expression: expression, @@ -50,7 +50,7 @@ public func expecta(fileID: String = #fileID, file: FileString = #f /// Make an ``AsyncExpectation`` on a given actual value. The closure is lazily invoked. /// This is provided to avoid confusion between `expect -> SyncExpectation` and `expect -> AsyncExpectation` -public func expecta(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, _ expression: @autoclosure @Sendable () -> (@Sendable () async throws -> sending T)) async -> AsyncExpectation { +public func expecta(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, _ expression: @autoclosure @Sendable () -> (@Sendable () async throws -> T)) async -> AsyncExpectation { return AsyncExpectation( expression: AsyncExpression( expression: expression(), @@ -60,7 +60,7 @@ public func expecta(fileID: String = #fileID, file: FileString = #f /// Make an ``AsyncExpectation`` on a given actual value. The closure is lazily invoked. /// This is provided to avoid confusion between `expect -> SyncExpectation` and `expect -> AsyncExpectation` -public func expecta(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, _ expression: @autoclosure @Sendable () -> (@Sendable () async throws -> sending T?)) async -> AsyncExpectation { +public func expecta(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, _ expression: @autoclosure @Sendable () -> (@Sendable () async throws -> T?)) async -> AsyncExpectation { return AsyncExpectation( expression: AsyncExpression( expression: expression(), @@ -70,7 +70,7 @@ public func expecta(fileID: String = #fileID, file: FileString = #f /// Make an ``AsyncExpectation`` on a given actual value. The closure is lazily invoked. /// This is provided to avoid confusion between `expect -> SyncExpectation` and `expect -> AsyncExpectation` -public func expecta(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, _ expression: @autoclosure @Sendable () -> (@Sendable () async throws -> sending Void)) async -> AsyncExpectation { +public func expecta(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, _ expression: @autoclosure @Sendable () -> (@Sendable () async throws -> Void)) async -> AsyncExpectation { return AsyncExpectation( expression: AsyncExpression( expression: expression(), diff --git a/Sources/Nimble/DSL+Require.swift b/Sources/Nimble/DSL+Require.swift index 952fadddb..b0b729851 100644 --- a/Sources/Nimble/DSL+Require.swift +++ b/Sources/Nimble/DSL+Require.swift @@ -3,7 +3,7 @@ /// `require` will return the result of the expression if the matcher passes, and throw an error if not. /// if a `customError` is given, then that will be thrown. Otherwise, a ``RequireError`` will be thrown. @discardableResult -public func require(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, customError: Error? = nil, _ expression: @autoclosure @escaping @Sendable () throws -> sending T?) -> SyncRequirement { +public func require(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, customError: Error? = nil, _ expression: @autoclosure @escaping @Sendable () throws -> T?) -> SyncRequirement { return SyncRequirement( expression: Expression( expression: expression, @@ -17,7 +17,7 @@ public func require(fileID: String = #fileID, file: FileString = #filePath, l /// `require` will return the result of the expression if the matcher passes, and throw an error if not. /// if a `customError` is given, then that will be thrown. Otherwise, a ``RequireError`` will be thrown. @discardableResult -public func require(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, customError: Error? = nil, _ expression: @autoclosure () -> (@Sendable () throws -> sending T)) -> SyncRequirement { +public func require(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, customError: Error? = nil, _ expression: @autoclosure () -> (@Sendable () throws -> T)) -> SyncRequirement { return SyncRequirement( expression: Expression( expression: expression(), @@ -31,7 +31,7 @@ public func require(fileID: String = #fileID, file: FileString = #filePath, l /// `require` will return the result of the expression if the matcher passes, and throw an error if not. /// if a `customError` is given, then that will be thrown. Otherwise, a ``RequireError`` will be thrown. @discardableResult -public func require(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, customError: Error? = nil, _ expression: @autoclosure () -> (@Sendable () throws -> sending T?)) -> SyncRequirement { +public func require(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, customError: Error? = nil, _ expression: @autoclosure () -> (@Sendable () throws -> T?)) -> SyncRequirement { return SyncRequirement( expression: Expression( expression: expression(), @@ -45,7 +45,7 @@ public func require(fileID: String = #fileID, file: FileString = #filePath, l /// `require` will return the result of the expression if the matcher passes, and throw an error if not. /// if a `customError` is given, then that will be thrown. Otherwise, a ``RequireError`` will be thrown. @discardableResult -public func require(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, customError: Error? = nil, _ expression: @autoclosure () -> (@Sendable () throws -> sending Void)) -> SyncRequirement { +public func require(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, customError: Error? = nil, _ expression: @autoclosure () -> (@Sendable () throws -> Void)) -> SyncRequirement { return SyncRequirement( expression: Expression( expression: expression(), @@ -61,7 +61,7 @@ public func require(fileID: String = #fileID, file: FileString = #filePath, line /// /// This is provided as an alternative to ``require``, for when you want to be specific about whether you're using ``SyncRequirement`` or ``AsyncRequirement``. @discardableResult -public func requires(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, customError: Error? = nil, _ expression: @autoclosure @escaping @Sendable () throws -> sending T?) -> SyncRequirement { +public func requires(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, customError: Error? = nil, _ expression: @autoclosure @escaping @Sendable () throws -> T?) -> SyncRequirement { return SyncRequirement( expression: Expression( expression: expression, @@ -77,7 +77,7 @@ public func requires(fileID: String = #fileID, file: FileString = #filePath, /// /// This is provided as an alternative to ``require``, for when you want to be specific about whether you're using ``SyncRequirement`` or ``AsyncRequirement``. @discardableResult -public func requires(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, customError: Error? = nil, _ expression: @autoclosure () -> (@Sendable () throws -> sending T)) -> SyncRequirement { +public func requires(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, customError: Error? = nil, _ expression: @autoclosure () -> (@Sendable () throws -> T)) -> SyncRequirement { return SyncRequirement( expression: Expression( expression: expression(), @@ -93,7 +93,7 @@ public func requires(fileID: String = #fileID, file: FileString = #filePath, /// /// This is provided as an alternative to ``require``, for when you want to be specific about whether you're using ``SyncRequirement`` or ``AsyncRequirement``. @discardableResult -public func requires(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, customError: Error? = nil, _ expression: @autoclosure () -> (@Sendable () throws -> sending T?)) -> SyncRequirement { +public func requires(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, customError: Error? = nil, _ expression: @autoclosure () -> (@Sendable () throws -> T?)) -> SyncRequirement { return SyncRequirement( expression: Expression( expression: expression(), @@ -109,7 +109,7 @@ public func requires(fileID: String = #fileID, file: FileString = #filePath, /// /// This is provided as an alternative to ``require``, for when you want to be specific about whether you're using ``SyncRequirement`` or ``AsyncRequirement``. @discardableResult -public func requires(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, customError: Error? = nil, _ expression: @autoclosure () -> (@Sendable () throws -> sending Void)) -> SyncRequirement { +public func requires(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, customError: Error? = nil, _ expression: @autoclosure () -> (@Sendable () throws -> Void)) -> SyncRequirement { return SyncRequirement( expression: Expression( expression: expression(), @@ -123,7 +123,7 @@ public func requires(fileID: String = #fileID, file: FileString = #filePath, lin /// `require` will return the result of the expression if the matcher passes, and throw an error if not. /// if a `customError` is given, then that will be thrown. Otherwise, a ``RequireError`` will be thrown. @discardableResult -public func require(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, customError: Error? = nil, _ expression: @escaping @Sendable () async throws -> sending T?) -> AsyncRequirement { +public func require(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, customError: Error? = nil, _ expression: @escaping @Sendable () async throws -> T?) -> AsyncRequirement { return AsyncRequirement( expression: AsyncExpression( expression: expression, @@ -137,7 +137,7 @@ public func require(fileID: String = #fileID, file: FileString = #f /// `require` will return the result of the expression if the matcher passes, and throw an error if not. /// if a `customError` is given, then that will be thrown. Otherwise, a ``RequireError`` will be thrown. @discardableResult -public func require(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, customError: Error? = nil, _ expression: () -> (@Sendable () async throws -> sending T)) -> AsyncRequirement { +public func require(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, customError: Error? = nil, _ expression: () -> (@Sendable () async throws -> T)) -> AsyncRequirement { return AsyncRequirement( expression: AsyncExpression( expression: expression(), @@ -151,7 +151,7 @@ public func require(fileID: String = #fileID, file: FileString = #f /// `require` will return the result of the expression if the matcher passes, and throw an error if not. /// if a `customError` is given, then that will be thrown. Otherwise, a ``RequireError`` will be thrown. @discardableResult -public func require(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, customError: Error? = nil, _ expression: () -> (@Sendable () async throws -> sending T?)) -> AsyncRequirement { +public func require(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, customError: Error? = nil, _ expression: () -> (@Sendable () async throws -> T?)) -> AsyncRequirement { return AsyncRequirement( expression: AsyncExpression( expression: expression(), @@ -167,7 +167,7 @@ public func require(fileID: String = #fileID, file: FileString = #f /// /// This is provided to avoid confusion between `require -> SyncRequirement` and `require -> AsyncRequirement`. @discardableResult -public func requirea(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, customError: Error? = nil, _ expression: @autoclosure @escaping @Sendable () async throws -> sending T?) async -> AsyncRequirement { +public func requirea(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, customError: Error? = nil, _ expression: @autoclosure @escaping @Sendable () async throws -> T?) async -> AsyncRequirement { return AsyncRequirement( expression: AsyncExpression( expression: expression, @@ -183,7 +183,7 @@ public func requirea(fileID: String = #fileID, file: FileString = # /// /// This is provided to avoid confusion between `require -> SyncRequirement` and `require -> AsyncRequirement` @discardableResult -public func requirea(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, customError: Error? = nil, _ expression: @autoclosure () -> (@Sendable () async throws -> sending T)) async -> AsyncRequirement { +public func requirea(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, customError: Error? = nil, _ expression: @autoclosure () -> (@Sendable () async throws -> T)) async -> AsyncRequirement { return AsyncRequirement( expression: AsyncExpression( expression: expression(), @@ -199,7 +199,7 @@ public func requirea(fileID: String = #fileID, file: FileString = # /// /// This is provided to avoid confusion between `require -> SyncRequirement` and `require -> AsyncRequirement` @discardableResult -public func requirea(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, customError: Error? = nil, _ expression: @autoclosure () -> (@Sendable () async throws -> sending T?)) async -> AsyncRequirement { +public func requirea(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, customError: Error? = nil, _ expression: @autoclosure () -> (@Sendable () async throws -> T?)) async -> AsyncRequirement { return AsyncRequirement( expression: AsyncExpression( expression: expression(), @@ -216,7 +216,7 @@ public func requirea(fileID: String = #fileID, file: FileString = # /// `unwrap` will return the result of the expression if it is non-nil, and throw an error if the value is nil. /// if a `customError` is given, then that will be thrown. Otherwise, a ``RequireError`` will be thrown. @discardableResult -public func unwrap(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, customError: Error? = nil, description: String? = nil, _ expression: @autoclosure @escaping @Sendable () throws -> sending T?) throws -> T { +public func unwrap(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, customError: Error? = nil, description: String? = nil, _ expression: @autoclosure @escaping @Sendable () throws -> T?) throws -> T { try requires(fileID: fileID, file: file, line: line, column: column, customError: customError, expression()).toNot(beNil(), description: description) } @@ -226,7 +226,7 @@ public func unwrap(fileID: String = #fileID, file: FileString = #filePath, li /// `unwrap` will return the result of the expression if it is non-nil, and throw an error if the value is nil. /// if a `customError` is given, then that will be thrown. Otherwise, a ``RequireError`` will be thrown. @discardableResult -public func unwrap(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, customError: Error? = nil, description: String? = nil, _ expression: @autoclosure () -> (@Sendable () throws -> sending T?)) throws -> T { +public func unwrap(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, customError: Error? = nil, description: String? = nil, _ expression: @autoclosure () -> (@Sendable () throws -> T?)) throws -> T { try requires(fileID: fileID, file: file, line: line, column: column, customError: customError, expression()).toNot(beNil(), description: description) } @@ -236,7 +236,7 @@ public func unwrap(fileID: String = #fileID, file: FileString = #filePath, li /// `unwraps` will return the result of the expression if it is non-nil, and throw an error if the value is nil. /// if a `customError` is given, then that will be thrown. Otherwise, a ``RequireError`` will be thrown. @discardableResult -public func unwraps(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, customError: Error? = nil, description: String? = nil, _ expression: @autoclosure @escaping @Sendable () throws -> sending T?) throws -> T { +public func unwraps(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, customError: Error? = nil, description: String? = nil, _ expression: @autoclosure @escaping @Sendable () throws -> T?) throws -> T { try requires(fileID: fileID, file: file, line: line, column: column, customError: customError, expression()).toNot(beNil(), description: description) } @@ -246,7 +246,7 @@ public func unwraps(fileID: String = #fileID, file: FileString = #filePath, l /// `unwraps` will return the result of the expression if it is non-nil, and throw an error if the value is nil. /// if a `customError` is given, then that will be thrown. Otherwise, a ``RequireError`` will be thrown. @discardableResult -public func unwraps(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, customError: Error? = nil, description: String? = nil, _ expression: @autoclosure () -> (@Sendable () throws -> sending T?)) throws -> T { +public func unwraps(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, customError: Error? = nil, description: String? = nil, _ expression: @autoclosure () -> (@Sendable () throws -> T?)) throws -> T { try requires(fileID: fileID, file: file, line: line, column: column, customError: customError, expression()).toNot(beNil(), description: description) } @@ -266,7 +266,7 @@ public func unwrap(fileID: String = #fileID, file: FileString = #fi /// `unwrap` will return the result of the expression if it is non-nil, and throw an error if the value is nil. /// if a `customError` is given, then that will be thrown. Otherwise, a ``RequireError`` will be thrown. @discardableResult -public func unwrap(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, customError: Error? = nil, description: String? = nil, _ expression: () -> (@Sendable () async throws -> sending T?)) async throws -> T { +public func unwrap(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, customError: Error? = nil, description: String? = nil, _ expression: () -> (@Sendable () async throws -> T?)) async throws -> T { try await requirea(fileID: fileID, file: file, line: line, column: column, customError: customError, expression()).toNot(beNil(), description: description) } @@ -286,7 +286,7 @@ public func unwrapa(fileID: String = #fileID, file: FileString = #f /// `unwrapa` will return the result of the expression if it is non-nil, and throw an error if the value is nil. /// if a `customError` is given, then that will be thrown. Otherwise, a ``RequireError`` will be thrown. @discardableResult -public func unwrapa(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, customError: Error? = nil, description: String? = nil, _ expression: @autoclosure () -> (@Sendable () async throws -> sending T?)) async throws -> T { +public func unwrapa(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, customError: Error? = nil, description: String? = nil, _ expression: @autoclosure () -> (@Sendable () async throws -> T?)) async throws -> T { try await requirea(fileID: fileID, file: file, line: line, column: column, customError: customError, expression()).toNot(beNil(), description: description) } diff --git a/Sources/Nimble/DSL.swift b/Sources/Nimble/DSL.swift index c93719acf..7595522e6 100644 --- a/Sources/Nimble/DSL.swift +++ b/Sources/Nimble/DSL.swift @@ -1,5 +1,5 @@ /// Make a ``SyncExpectation`` on a given actual value. The value given is lazily evaluated. -public func expect(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, _ expression: @autoclosure @escaping @Sendable () throws -> sending T?) -> SyncExpectation { +public func expect(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, _ expression: @autoclosure @escaping @Sendable () throws -> T?) -> SyncExpectation { return SyncExpectation( expression: Expression( expression: expression, @@ -8,7 +8,7 @@ public func expect(fileID: String = #fileID, file: FileString = #filePath, li } /// Make a ``SyncExpectation`` on a given actual value. The closure is lazily invoked. -public func expect(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, _ expression: @autoclosure () -> (@Sendable () throws -> sending T)) -> SyncExpectation { +public func expect(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, _ expression: @autoclosure () -> (@Sendable () throws -> T)) -> SyncExpectation { return SyncExpectation( expression: Expression( expression: expression(), @@ -17,7 +17,7 @@ public func expect(fileID: String = #fileID, file: FileString = #filePath, li } /// Make a ``SyncExpectation`` on a given actual value. The closure is lazily invoked. -public func expect(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, _ expression: @autoclosure () -> (@Sendable () throws -> sending T?)) -> SyncExpectation { +public func expect(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, _ expression: @autoclosure () -> (@Sendable () throws -> T?)) -> SyncExpectation { return SyncExpectation( expression: Expression( expression: expression(), @@ -26,7 +26,7 @@ public func expect(fileID: String = #fileID, file: FileString = #filePath, li } /// Make a ``SyncExpectation`` on a given actual value. The closure is lazily invoked. -public func expect(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, _ expression: @autoclosure () -> (@Sendable () throws -> sending Void)) -> SyncExpectation { +public func expect(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, _ expression: @autoclosure () -> (@Sendable () throws -> Void)) -> SyncExpectation { return SyncExpectation( expression: Expression( expression: expression(), @@ -36,7 +36,7 @@ public func expect(fileID: String = #fileID, file: FileString = #filePath, line: /// Make a ``SyncExpectation`` on a given actual value. The value given is lazily evaluated. /// This is provided as an alternative to `expect` which avoids overloading with `expect -> AsyncExpectation`. -public func expects(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, _ expression: @autoclosure @escaping @Sendable () throws -> sending T?) -> SyncExpectation { +public func expects(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, _ expression: @autoclosure @escaping @Sendable () throws -> T?) -> SyncExpectation { return SyncExpectation( expression: Expression( expression: expression, @@ -46,7 +46,7 @@ public func expects(fileID: String = #fileID, file: FileString = #filePath, l /// Make a ``SyncExpectation`` on a given actual value. The closure is lazily invoked. /// This is provided as an alternative to `expect` which avoids overloading with `expect -> AsyncExpectation`. -public func expects(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, _ expression: @autoclosure () -> (@Sendable () throws -> sending T)) -> SyncExpectation { +public func expects(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, _ expression: @autoclosure () -> (@Sendable () throws -> T)) -> SyncExpectation { return SyncExpectation( expression: Expression( expression: expression(), @@ -56,7 +56,7 @@ public func expects(fileID: String = #fileID, file: FileString = #filePath, l /// Make a ``SyncExpectation`` on a given actual value. The closure is lazily invoked. /// This is provided as an alternative to `expect` which avoids overloading with `expect -> AsyncExpectation`. -public func expects(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, _ expression: @autoclosure () -> (@Sendable () throws -> sending T?)) -> SyncExpectation { +public func expects(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, _ expression: @autoclosure () -> (@Sendable () throws -> T?)) -> SyncExpectation { return SyncExpectation( expression: Expression( expression: expression(), @@ -66,7 +66,7 @@ public func expects(fileID: String = #fileID, file: FileString = #filePath, l /// Make a ``SyncExpectation`` on a given actual value. The closure is lazily invoked. /// This is provided as an alternative to `expect` which avoids overloading with `expect -> AsyncExpectation`. -public func expects(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, _ expression: @autoclosure () -> (@Sendable () throws -> sending Void)) -> SyncExpectation { +public func expects(fileID: String = #fileID, file: FileString = #filePath, line: UInt = #line, column: UInt = #column, _ expression: @autoclosure () -> (@Sendable () throws -> Void)) -> SyncExpectation { // It would seem like `sending` isn't necessary for the `expression` argument // because the closure returns void. However, this gets rid of a type // conversion warning/error. diff --git a/Sources/Nimble/Expression.swift b/Sources/Nimble/Expression.swift index c41c7b5ef..8b91d4390 100644 --- a/Sources/Nimble/Expression.swift +++ b/Sources/Nimble/Expression.swift @@ -3,13 +3,13 @@ import Foundation private final class MemoizedValue: Sendable { private let lock = NSRecursiveLock() nonisolated(unsafe) private var cache: T? = nil - private let closure: @Sendable () throws -> sending T + private let closure: @Sendable () throws -> T - init(_ closure: @escaping @Sendable () throws -> sending T) { + init(_ closure: @escaping @Sendable () throws -> T) { self.closure = closure } - @Sendable func evaluate(withoutCaching: Bool) throws -> sending T { + @Sendable func evaluate(withoutCaching: Bool) throws -> T { try lock.withLock { if withoutCaching || cache == nil { cache = try closure() @@ -21,7 +21,7 @@ private final class MemoizedValue: Sendable { // Memoizes the given closure, only calling the passed // closure once; even if repeat calls to the returned closure -private func memoizedClosure(_ closure: @escaping @Sendable () throws -> sending T) -> @Sendable (Bool) throws -> sending T { +private func memoizedClosure(_ closure: @escaping @Sendable () throws -> T) -> @Sendable (Bool) throws -> T { MemoizedValue(closure).evaluate(withoutCaching:) } @@ -37,7 +37,7 @@ private func memoizedClosure(_ closure: @escaping @Sendable () throws -> send /// This provides a common consumable API for matchers to utilize to allow /// Nimble to change internals to how the captured closure is managed. public struct Expression: Sendable { - internal let _expression: @Sendable (Bool) throws -> sending Value? + internal let _expression: @Sendable (Bool) throws -> Value? internal let _withoutCaching: Bool public let location: SourceLocation public let isClosure: Bool @@ -53,7 +53,7 @@ public struct Expression: Sendable { /// requires an explicit closure. This gives Nimble /// flexibility if @autoclosure behavior changes between /// Swift versions. Nimble internals always sets this true. - public init(expression: @escaping @Sendable () throws -> sending Value?, location: SourceLocation, isClosure: Bool = true) { + public init(expression: @escaping @Sendable () throws -> Value?, location: SourceLocation, isClosure: Bool = true) { self._expression = memoizedClosure(expression) self.location = location self._withoutCaching = false @@ -74,7 +74,7 @@ public struct Expression: Sendable { /// requires an explicit closure. This gives Nimble /// flexibility if @autoclosure behavior changes between /// Swift versions. Nimble internals always sets this true. - public init(memoizedExpression: @escaping @Sendable (Bool) throws -> sending Value?, location: SourceLocation, withoutCaching: Bool, isClosure: Bool = true) { + public init(memoizedExpression: @escaping @Sendable (Bool) throws -> Value?, location: SourceLocation, withoutCaching: Bool, isClosure: Bool = true) { self._expression = memoizedExpression self.location = location self._withoutCaching = withoutCaching @@ -89,7 +89,7 @@ public struct Expression: Sendable { /// /// - Parameter block: The block that can cast the current Expression value to a /// new type. - public func cast(_ block: @escaping @Sendable (Value?) throws -> sending U?) -> Expression { + public func cast(_ block: @escaping @Sendable (Value?) throws -> U?) -> Expression { Expression( expression: ({ try block(self.evaluate()) }), location: self.location, diff --git a/Sources/Nimble/Matchers/Equal.swift b/Sources/Nimble/Matchers/Equal.swift index 1a5ce0173..4d4c00b02 100644 --- a/Sources/Nimble/Matchers/Equal.swift +++ b/Sources/Nimble/Matchers/Equal.swift @@ -44,7 +44,7 @@ public func equal(_ expectedValue: [T?]) -> Matcher<[T?]> { /// /// @see beCloseTo if you want to match imprecise types (eg - floats, doubles). public func equal(_ expectedValue: T?) -> Matcher { - equal(expectedValue, by: ==) + equal(expectedValue, by: { $0 == $1 }) } /// A Nimble matcher that succeeds when the actual set is equal to the expected set. diff --git a/Sources/Nimble/Matchers/Matcher.swift b/Sources/Nimble/Matchers/Matcher.swift index 470985f60..ffb5798b5 100644 --- a/Sources/Nimble/Matchers/Matcher.swift +++ b/Sources/Nimble/Matchers/Matcher.swift @@ -225,7 +225,7 @@ public class NMBMatcher: NSObject, @unchecked Sendable { self.init(matcher: predicate) } - func satisfies(_ expression: @escaping @Sendable () throws -> sending NSObject?, location: SourceLocation) -> NMBMatcherResult { + func satisfies(_ expression: @escaping @Sendable () throws -> NSObject?, location: SourceLocation) -> NMBMatcherResult { let expr = Expression(expression: expression, location: location) do { return try self.matcher(expr) diff --git a/Sources/Nimble/Polling+Require.swift b/Sources/Nimble/Polling+Require.swift index 4f42f442d..17a3fffac 100644 --- a/Sources/Nimble/Polling+Require.swift +++ b/Sources/Nimble/Polling+Require.swift @@ -715,7 +715,7 @@ public func pollUnwrap(file: FileString = #file, line: UInt = #line, _ expres /// Makes sure that the expression evaluates to a non-nil value, otherwise throw an error. /// As you can tell, this is a much less verbose equivalent to `require(expression).toEventuallyNot(beNil())` @discardableResult -public func pollUnwrap(file: FileString = #file, line: UInt = #line, timeout: NimbleTimeInterval = PollingDefaults.timeout, pollInterval: NimbleTimeInterval = PollingDefaults.pollInterval, description: String? = nil, _ expression: @autoclosure () -> (@Sendable () throws -> sending T?)) throws -> T { +public func pollUnwrap(file: FileString = #file, line: UInt = #line, timeout: NimbleTimeInterval = PollingDefaults.timeout, pollInterval: NimbleTimeInterval = PollingDefaults.pollInterval, description: String? = nil, _ expression: @autoclosure () -> (@Sendable () throws -> T?)) throws -> T { try require(file: file, line: line, expression()).toEventuallyNot(beNil(), timeout: timeout, pollInterval: pollInterval, description: description) } @@ -729,7 +729,7 @@ public func pollUnwraps(file: FileString = #file, line: UInt = #line, timeout /// Makes sure that the expression evaluates to a non-nil value, otherwise throw an error. /// As you can tell, this is a much less verbose equivalent to `require(expression).toEventuallyNot(beNil())` @discardableResult -public func pollUnwraps(file: FileString = #file, line: UInt = #line, timeout: NimbleTimeInterval = PollingDefaults.timeout, pollInterval: NimbleTimeInterval = PollingDefaults.pollInterval, description: String? = nil, _ expression: @autoclosure () -> (@Sendable () throws -> sending T?)) throws -> T { +public func pollUnwraps(file: FileString = #file, line: UInt = #line, timeout: NimbleTimeInterval = PollingDefaults.timeout, pollInterval: NimbleTimeInterval = PollingDefaults.pollInterval, description: String? = nil, _ expression: @autoclosure () -> (@Sendable () throws -> T?)) throws -> T { try require(file: file, line: line, expression()).toEventuallyNot(beNil(), timeout: timeout, pollInterval: pollInterval, description: description) } diff --git a/Sources/Nimble/Utils/PollAwait.swift b/Sources/Nimble/Utils/PollAwait.swift index b56eef6ab..5f5913460 100644 --- a/Sources/Nimble/Utils/PollAwait.swift +++ b/Sources/Nimble/Utils/PollAwait.swift @@ -316,7 +316,7 @@ internal class Awaiter { func performBlock( file: FileString, line: UInt, - _ closure: sending @escaping (@escaping @Sendable (T) -> Void) throws -> Void + _ closure: @escaping (@escaping @Sendable (T) -> Void) throws -> Void ) -> AwaitPromiseBuilder { let promise = AwaitPromise() let timeoutSource = createTimerSource(timeoutQueue) diff --git a/Tests/NimbleTests/Matchers/NegationTest.swift b/Tests/NimbleTests/Matchers/NegationTest.swift index 4929988ba..45d35f39a 100644 --- a/Tests/NimbleTests/Matchers/NegationTest.swift +++ b/Tests/NimbleTests/Matchers/NegationTest.swift @@ -22,7 +22,7 @@ final class NegationTest: XCTestCase { } func testAsyncNil() async { - @Sendable func nilFunc() async -> sending Int? { + @Sendable func nilFunc() async -> Int? { nil }