Skip to content

Commit

Permalink
Make XCTestContext sendable (#74)
Browse files Browse the repository at this point in the history
With concurrency warnings dialed up, this type can cause warnings to be
emitted, but as a task local should be safe to pass along.
  • Loading branch information
stephencelis authored Jan 22, 2024
1 parent 89a3632 commit 104326b
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 121 deletions.
4 changes: 2 additions & 2 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// swift-tools-version:5.5
// swift-tools-version:5.7

import PackageDescription

Expand All @@ -22,7 +22,7 @@ let package = Package(
]
)

#if swift(>=5.6) && !os(Windows)
#if !os(Windows)
// Add the documentation compiler plugin if possible
package.dependencies.append(
.package(url: "https://github.com/apple/swift-docc-plugin", from: "1.0.0")
Expand Down
144 changes: 26 additions & 118 deletions Sources/XCTestDynamicOverlay/Internal/GeneratePlaceholder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,133 +17,41 @@ private func _optionalPlaceholder<Result>() throws -> Result {
throw PlaceholderGenerationFailure()
}

#if swift(>=5.7)
private func _placeholder<Result>() -> Result? {
switch Result.self {
case let type as _DefaultInitializable.Type: return type.placeholder as? Result
case is Void.Type: return () as? Result
case let type as any RangeReplaceableCollection.Type: return type.placeholder as? Result
case let type as any AdditiveArithmetic.Type: return type.placeholder as? Result
case let type as any ExpressibleByArrayLiteral.Type: return type.placeholder as? Result
case let type as any ExpressibleByBooleanLiteral.Type: return type.placeholder as? Result
case let type as any ExpressibleByDictionaryLiteral.Type: return type.placeholder as? Result
case let type as any ExpressibleByFloatLiteral.Type: return type.placeholder as? Result
case let type as any ExpressibleByIntegerLiteral.Type: return type.placeholder as? Result
case let type as any ExpressibleByUnicodeScalarLiteral.Type: return type.placeholder as? Result
default: return nil
}
}

private func _rawRepresentable<Result>() -> Result? {
func posiblePlaceholder<T: RawRepresentable>(for type: T.Type) -> T? {
(_placeholder() as T.RawValue?).flatMap(T.init(rawValue:))
}

return (Result.self as? any RawRepresentable.Type).flatMap {
posiblePlaceholder(for: $0) as? Result
}
}

private func _caseIterable<Result>() -> Result? {
func firstCase<T: CaseIterable>(for type: T.Type) -> Result? {
T.allCases.first as? Result
}

return (Result.self as? any CaseIterable.Type).flatMap {
firstCase(for: $0)
}
}
#else
private func _placeholder<Result>() -> Result? {
if let result = (Result.self as? _DefaultInitializable.Type)?.placeholder {
return result as? Result
}

if Result.self == Void.self {
return () as? Result
}

switch Witness<Result>.self {
case let type as AnyRangeReplaceableCollection.Type: return type.placeholder as? Result
case let type as AnyAdditiveArithmetic.Type: return type.placeholder as? Result
case let type as AnyExpressibleByArrayLiteral.Type: return type.placeholder as? Result
case let type as AnyExpressibleByBooleanLiteral.Type: return type.placeholder as? Result
case let type as AnyExpressibleByDictionaryLiteral.Type: return type.placeholder as? Result
case let type as AnyExpressibleByFloatLiteral.Type: return type.placeholder as? Result
case let type as AnyExpressibleByIntegerLiteral.Type: return type.placeholder as? Result
case let type as AnyExpressibleByUnicodeScalarLiteral.Type: return type.placeholder as? Result
default: return nil
}
}

private func _rawRepresentable<Result>() -> Result? {
(Witness<Result>.self as? AnyRawRepresentable.Type).flatMap {
$0.possiblePlaceholder as? Result
}
}

private func _caseIterable<Result>() -> Result? {
(Witness<Result>.self as? AnyCaseIterable.Type).flatMap {
$0.firstCase as? Result
}
}

private enum Witness<Value> {}
private protocol AnyAdditiveArithmetic { static var placeholder: Any { get } }
extension Witness: AnyAdditiveArithmetic where Value: AdditiveArithmetic {
fileprivate static var placeholder: Any { Value.placeholder }
}

private protocol AnyExpressibleByArrayLiteral { static var placeholder: Any { get } }
extension Witness: AnyExpressibleByArrayLiteral where Value: ExpressibleByArrayLiteral {
fileprivate static var placeholder: Any { Value.placeholder }
}

private protocol AnyExpressibleByBooleanLiteral { static var placeholder: Any { get } }
extension Witness: AnyExpressibleByBooleanLiteral where Value: ExpressibleByBooleanLiteral {
fileprivate static var placeholder: Any { Value.placeholder }
}

private protocol AnyExpressibleByDictionaryLiteral { static var placeholder: Any { get } }
extension Witness: AnyExpressibleByDictionaryLiteral where Value: ExpressibleByDictionaryLiteral {
fileprivate static var placeholder: Any { Value.placeholder }
}

private protocol AnyExpressibleByFloatLiteral { static var placeholder: Any { get } }
extension Witness: AnyExpressibleByFloatLiteral where Value: ExpressibleByFloatLiteral {
fileprivate static var placeholder: Any { Value.placeholder }
}

private protocol AnyExpressibleByIntegerLiteral { static var placeholder: Any { get } }
extension Witness: AnyExpressibleByIntegerLiteral where Value: ExpressibleByIntegerLiteral {
fileprivate static var placeholder: Any { Value.placeholder }
private func _placeholder<Result>() -> Result? {
switch Result.self {
case let type as _DefaultInitializable.Type: return type.placeholder as? Result
case is Void.Type: return () as? Result
case let type as any RangeReplaceableCollection.Type: return type.placeholder as? Result
case let type as any AdditiveArithmetic.Type: return type.placeholder as? Result
case let type as any ExpressibleByArrayLiteral.Type: return type.placeholder as? Result
case let type as any ExpressibleByBooleanLiteral.Type: return type.placeholder as? Result
case let type as any ExpressibleByDictionaryLiteral.Type: return type.placeholder as? Result
case let type as any ExpressibleByFloatLiteral.Type: return type.placeholder as? Result
case let type as any ExpressibleByIntegerLiteral.Type: return type.placeholder as? Result
case let type as any ExpressibleByUnicodeScalarLiteral.Type: return type.placeholder as? Result
default: return nil
}
}

private protocol AnyExpressibleByUnicodeScalarLiteral { static var placeholder: Any { get } }
extension Witness: AnyExpressibleByUnicodeScalarLiteral
where Value: ExpressibleByUnicodeScalarLiteral {
fileprivate static var placeholder: Any { Value.placeholder }
private func _rawRepresentable<Result>() -> Result? {
func posiblePlaceholder<T: RawRepresentable>(for type: T.Type) -> T? {
(_placeholder() as T.RawValue?).flatMap(T.init(rawValue:))
}

private protocol AnyRangeReplaceableCollection { static var placeholder: Any { get } }
extension Witness: AnyRangeReplaceableCollection where Value: RangeReplaceableCollection {
fileprivate static var placeholder: Any { Value.placeholder }
return (Result.self as? any RawRepresentable.Type).flatMap {
posiblePlaceholder(for: $0) as? Result
}
}

private protocol AnyRawRepresentable { static var possiblePlaceholder: Any? { get } }
extension Witness: AnyRawRepresentable where Value: RawRepresentable {
fileprivate static var possiblePlaceholder: Any? {
(_placeholder() as Value.RawValue?).flatMap(Value.init(rawValue:))
}
private func _caseIterable<Result>() -> Result? {
func firstCase<T: CaseIterable>(for type: T.Type) -> Result? {
T.allCases.first as? Result
}

private protocol AnyCaseIterable { static var firstCase: Any? { get } }
extension Witness: AnyCaseIterable where Value: CaseIterable {
fileprivate static var firstCase: Any? {
Value.allCases.first
}
return (Result.self as? any CaseIterable.Type).flatMap {
firstCase(for: $0)
}
#endif
}

struct PlaceholderGenerationFailure: Error {}
func _generatePlaceholder<Result>() throws -> Result {
Expand Down
2 changes: 1 addition & 1 deletion Sources/XCTestDynamicOverlay/XCTFail.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

public struct XCTFailContext {
public struct XCTFailContext: Sendable {
@TaskLocal public static var current: Self?

public var file: StaticString
Expand Down

0 comments on commit 104326b

Please sign in to comment.