From e4ea35982bf0df8d34cb1153f93b326aecb64842 Mon Sep 17 00:00:00 2001 From: Dan Federman Date: Fri, 21 Jun 2024 09:57:54 -0700 Subject: [PATCH] Make `Instantiator` and `ErasedInstantiator` no longer @MainActor-bound (#87) Removes NonisolatedInstantiator and NonisolatedErasedInstantiator, and adds SendableInstantiator and SendableErasedInstantiator. --- README.md | 4 +- .../ErasedInstantiator.swift | 14 ++-- .../DelayedInstantiation/Instantiator.swift | 14 ++-- ...swift => SendableErasedInstantiator.swift} | 12 +-- ...iator.swift => SendableInstantiator.swift} | 12 +-- .../Generators/ScopeGenerator.swift | 12 +-- Sources/SafeDICore/Models/Dependency.swift | 4 +- Sources/SafeDICore/Models/Property.swift | 26 +++--- .../SafeDICore/Models/TypeDescription.swift | 12 +-- .../SafeDIMacros/Macros/InjectableMacro.swift | 4 +- .../InjectableMacroTests.swift | 4 +- ... => SendableErasedInstantiatorTests.swift} | 6 +- ....swift => SendableInstantiatorTests.swift} | 6 +- Tests/SafeDIToolTests/SafeDIToolTests.swift | 84 +++++++++---------- 14 files changed, 103 insertions(+), 111 deletions(-) rename Sources/SafeDI/DelayedInstantiation/{NonisolatedErasedInstantiator.swift => SendableErasedInstantiator.swift} (81%) rename Sources/SafeDI/DelayedInstantiation/{NonisolatedInstantiator.swift => SendableInstantiator.swift} (83%) rename Tests/SafeDITests/{NonisolatedErasedInstantiatorTests.swift => SendableErasedInstantiatorTests.swift} (88%) rename Tests/SafeDITests/{NonisolatedInstantiatorTests.swift => SendableInstantiatorTests.swift} (89%) diff --git a/README.md b/README.md index b5d43657..a7afb7a1 100644 --- a/README.md +++ b/README.md @@ -291,7 +291,7 @@ public struct MyApp: App, Instantiable { } ``` -An `Instantiator` is `@MainActor`-bound – if you want to instantiate a type in a nonisolated environment, use a [`NonisolatedInstantiator`](Sources/SafeDI/DelayedInstantiation/NonisolatedInstantiator.swift). +An `Instantiator` is not `Sendable` – if you want to be able to share an instantiator across concurrency domains, use a [`SendableInstantiator`](Sources/SafeDI/DelayedInstantiation/SendableInstantiator.swift). #### Utilizing @Instantiated with type erased properties @@ -301,7 +301,7 @@ The `fulfilledByType` parameter takes a `String` identical to the type name of t The `erasedToConcreteExistential` parameter takes a boolean value that indicates whether the fulfilling type is being erased to a concrete [existential](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/opaquetypes/#Boxed-Protocol-Types) type. A concrete existential type is a non-protocol type that wraps a protocol and is usually prefixed with `Any`. A fulfilling type does not inherit from a concrete existential type, and therefore when the property‘s type is a concrete existential the fulfilling type must be wrapped in the erasing concrete existential type‘s initializer before it is returned. When the property‘s type is not a concrete existential, the fulfilling type is cast as the property‘s type. For example, an `AnyView` is a concrete and existential type-erased form of some `struct MyExampleView: View`, while a `UIViewController` is a concrete but not existential type-erased form of some `final class MyExampleViewController: UIViewController`. This parameter defaults to `false`. -The [`ErasedInstantiator`](Sources/SafeDI/DelayedInstantiation/ErasedInstantiator.swift) type is how SafeDI enables instantiating any `@Instantiable` type when using type erasure. `ErasedInstantiator` has two generics. The first generic must match the type’s `ForwardedProperties` typealias. The second generic matches the type of the to-be-instantiated instance. An `ErasedInstantiator` is `@MainActor`-bound – if you want to instantiate an erased type in a nonisolated environment, use a [`NonisolatedErasedInstantiator`](Sources/SafeDI/DelayedInstantiation/NonisolatedErasedInstantiator.swift). +The [`ErasedInstantiator`](Sources/SafeDI/DelayedInstantiation/ErasedInstantiator.swift) type is how SafeDI enables instantiating any `@Instantiable` type when using type erasure. `ErasedInstantiator` has two generics. The first generic must match the type’s `ForwardedProperties` typealias. The second generic matches the type of the to-be-instantiated instance. An `ErasedInstantiator` is not `Sendable` – if you want to be able to share an erased instantiator across concurrency domains, use a [`SendableErasedInstantiator`](Sources/SafeDI/DelayedInstantiation/SendableErasedInstantiator.swift). ```swift import SwiftUI diff --git a/Sources/SafeDI/DelayedInstantiation/ErasedInstantiator.swift b/Sources/SafeDI/DelayedInstantiation/ErasedInstantiator.swift index 6068fa7d..f6039f9a 100644 --- a/Sources/SafeDI/DelayedInstantiation/ErasedInstantiator.swift +++ b/Sources/SafeDI/DelayedInstantiation/ErasedInstantiator.swift @@ -21,19 +21,17 @@ /// A SafeDI dependency designed for the deferred instantiation of a type-erased instance of a /// type decorated with `@Instantiable`. /// -/// This instantiator can be used to instantiate types that are @MainActor-bound. -/// /// - SeeAlso: `Instantiator` -/// - SeeAlso: `NonisolatedInstantiator` -/// - SeeAlso: `NonisolatedErasedInstantiator` +/// - SeeAlso: `SendableInstantiator` +/// - SeeAlso: `SendableErasedInstantiator` public final class ErasedInstantiator { /// - Parameter instantiator: A closure that takes `ForwardedProperties` and returns an instance of `Instantiable`. - public init(_ instantiator: @escaping @MainActor (ForwardedProperties) -> Instantiable) { + public init(_ instantiator: @escaping (ForwardedProperties) -> Instantiable) { self.instantiator = instantiator } /// - Parameter instantiator: A closure that returns an instance of `Instantiable`. - public init(_ instantiator: @escaping @MainActor () -> Instantiable) where ForwardedProperties == Void { + public init(_ instantiator: @escaping () -> Instantiable) where ForwardedProperties == Void { self.instantiator = { _ in instantiator() } } @@ -41,7 +39,6 @@ public final class ErasedInstantiator { /// /// - Parameter arguments: Arguments required for instantiation. /// - Returns: An `Instantiable` instance. - @MainActor public func instantiate(_ arguments: ForwardedProperties) -> Instantiable { instantiator(arguments) } @@ -49,10 +46,9 @@ public final class ErasedInstantiator { /// Instantiates and returns a new instance of the `@Instantiable` type. /// /// - Returns: An `Instantiable` instance. - @MainActor public func instantiate() -> Instantiable where ForwardedProperties == Void { instantiator(()) } - private let instantiator: @MainActor (ForwardedProperties) -> Instantiable + private let instantiator: (ForwardedProperties) -> Instantiable } diff --git a/Sources/SafeDI/DelayedInstantiation/Instantiator.swift b/Sources/SafeDI/DelayedInstantiation/Instantiator.swift index c93871c2..f2deb8cf 100644 --- a/Sources/SafeDI/DelayedInstantiation/Instantiator.swift +++ b/Sources/SafeDI/DelayedInstantiation/Instantiator.swift @@ -23,35 +23,31 @@ /// useful in scenarios where immediate instantiation is not necessary or desirable. `Instantiator` /// facilitates control over memory usage and enables just-in-time instantiation. /// -/// This instantiator can be used to instantiate types that are @MainActor-bound. -/// /// - SeeAlso: `ErasedInstantiator` -/// - SeeAlso: `NonisolatedInstantiator` -/// - SeeAlso: `NonisolatedErasedInstantiator` +/// - SeeAlso: `SendableInstantiator` +/// - SeeAlso: `SendableErasedInstantiator` public final class Instantiator { /// - Parameter instantiator: A closure that returns an instance of `Instantiable`. - public init(_ instantiator: @escaping @MainActor (T.ForwardedProperties) -> T) { + public init(_ instantiator: @escaping (T.ForwardedProperties) -> T) { self.instantiator = instantiator } /// - Parameter instantiator: A closure that returns an instance of `Instantiable`. - public init(_ instantiator: @escaping @MainActor () -> T) where T.ForwardedProperties == Void { + public init(_ instantiator: @escaping () -> T) where T.ForwardedProperties == Void { self.instantiator = { _ in instantiator() } } /// Instantiates and returns a new instance of the `@Instantiable` type. /// - Returns: An instance of `T`. - @MainActor public func instantiate(_ forwardedProperties: T.ForwardedProperties) -> T { instantiator(forwardedProperties) } /// Instantiates and returns a new instance of the `@Instantiable` type. /// - Returns: An instance of `T`. - @MainActor public func instantiate() -> T where T.ForwardedProperties == Void { instantiator(()) } - private let instantiator: @MainActor (T.ForwardedProperties) -> T + private let instantiator: (T.ForwardedProperties) -> T } diff --git a/Sources/SafeDI/DelayedInstantiation/NonisolatedErasedInstantiator.swift b/Sources/SafeDI/DelayedInstantiation/SendableErasedInstantiator.swift similarity index 81% rename from Sources/SafeDI/DelayedInstantiation/NonisolatedErasedInstantiator.swift rename to Sources/SafeDI/DelayedInstantiation/SendableErasedInstantiator.swift index 57cd0b76..780d0acc 100644 --- a/Sources/SafeDI/DelayedInstantiation/NonisolatedErasedInstantiator.swift +++ b/Sources/SafeDI/DelayedInstantiation/SendableErasedInstantiator.swift @@ -21,19 +21,19 @@ /// A SafeDI dependency designed for the deferred instantiation of a type-erased instance of a /// type decorated with `@Instantiable`. /// -/// This instantiator can be used to instantiate types that are not isolated to any particular actor. +/// This instantiator can be used to instantiate types across concurrency domains. /// /// - SeeAlso: `Instantiator` -/// - SeeAlso: `NonisolatedInstantiator` +/// - SeeAlso: `SendableInstantiator` /// - SeeAlso: `ErasedInstantiator` -public final class NonisolatedErasedInstantiator { +public final class SendableErasedInstantiator: Sendable { /// - Parameter instantiator: A closure that takes `ForwardedProperties` and returns an instance of `Instantiable`. - public init(_ instantiator: @escaping (ForwardedProperties) -> Instantiable) { + public init(_ instantiator: @escaping @Sendable (ForwardedProperties) -> Instantiable) { self.instantiator = instantiator } /// - Parameter instantiator: A closure that returns an instance of `Instantiable`. - public init(_ instantiator: @escaping () -> Instantiable) where ForwardedProperties == Void { + public init(_ instantiator: @escaping @Sendable () -> Instantiable) where ForwardedProperties == Void { self.instantiator = { _ in instantiator() } } @@ -52,5 +52,5 @@ public final class NonisolatedErasedInstantiator Instantiable + private let instantiator: @Sendable (ForwardedProperties) -> Instantiable } diff --git a/Sources/SafeDI/DelayedInstantiation/NonisolatedInstantiator.swift b/Sources/SafeDI/DelayedInstantiation/SendableInstantiator.swift similarity index 83% rename from Sources/SafeDI/DelayedInstantiation/NonisolatedInstantiator.swift rename to Sources/SafeDI/DelayedInstantiation/SendableInstantiator.swift index 84938930..3aef61f5 100644 --- a/Sources/SafeDI/DelayedInstantiation/NonisolatedInstantiator.swift +++ b/Sources/SafeDI/DelayedInstantiation/SendableInstantiator.swift @@ -23,19 +23,19 @@ /// useful in scenarios where immediate instantiation is not necessary or desirable. `Instantiator` /// facilitates control over memory usage and enables just-in-time instantiation. /// -/// This instantiator can be used to instantiate types that are not isolated to any particular actor. +/// This instantiator can be used to instantiate types across concurrency domains. /// /// - SeeAlso: `Instantiator` /// - SeeAlso: `ErasedInstantiator` -/// - SeeAlso: `NonisolatedErasedInstantiator` -public final class NonisolatedInstantiator { +/// - SeeAlso: `SendableErasedInstantiator` +public final class SendableInstantiator: Sendable { /// - Parameter instantiator: A closure that returns an instance of `Instantiable`. - public init(_ instantiator: @escaping (T.ForwardedProperties) -> T) { + public init(_ instantiator: @escaping @Sendable (T.ForwardedProperties) -> T) { self.instantiator = instantiator } /// - Parameter instantiator: A closure that returns an instance of `Instantiable`. - public init(_ instantiator: @escaping () -> T) where T.ForwardedProperties == Void { + public init(_ instantiator: @escaping @Sendable () -> T) where T.ForwardedProperties == Void { self.instantiator = { _ in instantiator() } } @@ -51,5 +51,5 @@ public final class NonisolatedInstantiator { instantiator(()) } - private let instantiator: (T.ForwardedProperties) -> T + private let instantiator: @Sendable (T.ForwardedProperties) -> T } diff --git a/Sources/SafeDICore/Generators/ScopeGenerator.swift b/Sources/SafeDICore/Generators/ScopeGenerator.swift index 3b0697d5..d2b1b17d 100644 --- a/Sources/SafeDICore/Generators/ScopeGenerator.swift +++ b/Sources/SafeDICore/Generators/ScopeGenerator.swift @@ -164,8 +164,8 @@ actor ScopeGenerator: CustomStringConvertible { switch propertyType { case .instantiator, .erasedInstantiator, - .nonisolatedInstantiator, - .nonisolatedErasedInstantiator: + .sendableInstantiator, + .sendableErasedInstantiator: let forwardedProperties = forwardedProperties.sorted() let forwardedPropertiesHaveLabels = forwardedProperties.count > 1 let forwardedArguments = forwardedProperties @@ -184,16 +184,16 @@ actor ScopeGenerator: CustomStringConvertible { forwardedProperties.initializerFunctionParameters.map(\.description).joined() } let functionName = self.functionName(toBuild: property) - let actorBinding = if propertyType.isMainActorBound { - "@MainActor " + let functionDecorator = if propertyType.isSendable { + "@Sendable " } else { - "nonisolated " + "" } let functionDeclaration = if isPropertyCycle { "" } else { """ - \(actorBinding)func \(functionName)(\(functionArguments)) -> \(concreteTypeName) { + \(functionDecorator)func \(functionName)(\(functionArguments)) -> \(concreteTypeName) { \(generatedProperties.joined(separator: "\n")) \(Self.standardIndent)\(generatedProperties.isEmpty ? "" : "return ")\(returnLineSansReturn) } diff --git a/Sources/SafeDICore/Models/Dependency.swift b/Sources/SafeDICore/Models/Dependency.swift index 8a83abdf..374f3fa9 100644 --- a/Sources/SafeDICore/Models/Dependency.swift +++ b/Sources/SafeDICore/Models/Dependency.swift @@ -93,6 +93,6 @@ public struct Dependency: Codable, Hashable { static let instantiatorType = "Instantiator" static let erasedInstantiatorType = "ErasedInstantiator" - static let nonisolatedInstantiatorType = "NonisolatedInstantiator" - static let nonisolatedErasedInstantiatorType = "NonisolatedErasedInstantiator" + static let sendableInstantiatorType = "SendableInstantiator" + static let sendableErasedInstantiatorType = "SendableErasedInstantiator" } diff --git a/Sources/SafeDICore/Models/Property.swift b/Sources/SafeDICore/Models/Property.swift index 55d1308f..3016fce7 100644 --- a/Sources/SafeDICore/Models/Property.swift +++ b/Sources/SafeDICore/Models/Property.swift @@ -138,46 +138,46 @@ public struct Property: Codable, Hashable, Comparable, Sendable { /// An `ErasedInstantiator` property. /// The instantiated product is not forwarded down the dependency tree. This is done intentionally to avoid unexpected retains. case erasedInstantiator - /// A `NonisolatedInstantiator` property. + /// A `SendableInstantiator` property. /// The instantiated product is not forwarded down the dependency tree. This is done intentionally to avoid unexpected retains. - case nonisolatedInstantiator - /// A `NonisolatedErasedInstantiator` property. + case sendableInstantiator + /// A `SendableErasedInstantiator` property. /// The instantiated product is not forwarded down the dependency tree. This is done intentionally to avoid unexpected retains. - case nonisolatedErasedInstantiator + case sendableErasedInstantiator public var isConstant: Bool { switch self { case .constant: true - case .instantiator, .erasedInstantiator, .nonisolatedInstantiator, .nonisolatedErasedInstantiator: + case .instantiator, .erasedInstantiator, .sendableInstantiator, .sendableErasedInstantiator: false } } public var isInstantiator: Bool { switch self { - case .instantiator, .nonisolatedInstantiator: + case .instantiator, .sendableInstantiator: true - case .constant, .erasedInstantiator, .nonisolatedErasedInstantiator: + case .constant, .erasedInstantiator, .sendableErasedInstantiator: false } } public var isErasedInstantiator: Bool { switch self { - case .erasedInstantiator, .nonisolatedErasedInstantiator: + case .erasedInstantiator, .sendableErasedInstantiator: true - case .constant, .instantiator, .nonisolatedInstantiator: + case .constant, .instantiator, .sendableInstantiator: false } } - public var isMainActorBound: Bool { + public var isSendable: Bool { switch self { - case .instantiator, .erasedInstantiator: - true - case .constant, .nonisolatedInstantiator, .nonisolatedErasedInstantiator: + case .instantiator, .erasedInstantiator, .constant: false + case .sendableInstantiator, .sendableErasedInstantiator: + true } } } diff --git a/Sources/SafeDICore/Models/TypeDescription.swift b/Sources/SafeDICore/Models/TypeDescription.swift index 0a5cfe59..11342770 100644 --- a/Sources/SafeDICore/Models/TypeDescription.swift +++ b/Sources/SafeDICore/Models/TypeDescription.swift @@ -184,10 +184,10 @@ public enum TypeDescription: Codable, Hashable, Comparable, Sendable { .instantiator } else if name == Dependency.erasedInstantiatorType { .erasedInstantiator - } else if name == Dependency.nonisolatedInstantiatorType { - .nonisolatedInstantiator - } else if name == Dependency.nonisolatedErasedInstantiatorType { - .nonisolatedErasedInstantiator + } else if name == Dependency.sendableInstantiatorType { + .sendableInstantiator + } else if name == Dependency.sendableErasedInstantiatorType { + .sendableErasedInstantiator } else { .constant } @@ -248,13 +248,13 @@ public enum TypeDescription: Codable, Hashable, Comparable, Sendable { var asInstantiatedType: TypeDescription { switch self { case let .simple(name, generics): - if name == Dependency.instantiatorType || name == Dependency.nonisolatedInstantiatorType, + if name == Dependency.instantiatorType || name == Dependency.sendableInstantiatorType, let builtType = generics.first { // This is a type that is lazily instantiated. // The first generic is the built type. builtType - } else if name == Dependency.erasedInstantiatorType || name == Dependency.nonisolatedErasedInstantiatorType, + } else if name == Dependency.erasedInstantiatorType || name == Dependency.sendableErasedInstantiatorType, let builtType = generics.dropFirst().first { // This is a type that is lazily instantiated with explicitly declared forwarded arguments due to type erasure. diff --git a/Sources/SafeDIMacros/Macros/InjectableMacro.swift b/Sources/SafeDIMacros/Macros/InjectableMacro.swift index 72d19328..ff45ae58 100644 --- a/Sources/SafeDIMacros/Macros/InjectableMacro.swift +++ b/Sources/SafeDIMacros/Macros/InjectableMacro.swift @@ -145,13 +145,13 @@ public struct InjectableMacro: PeerMacro { case .fulfilledByDependencyNamedInvalidType: "The argument `fulfilledByDependencyNamed` must be a string literal" case .fulfilledByTypeUseOnInstantiator: - "The argument `fulfilledByType` can not be used on an `Instantiator` or `NonisolatedInstantiator`. Use an `ErasedInstantiator` or `NonisolatedErasedInstantiator` instead" + "The argument `fulfilledByType` can not be used on an `Instantiator` or `SendableInstantiator`. Use an `ErasedInstantiator` or `SendableErasedInstantiator` instead" case .ofTypeArgumentInvalidType: "The argument `ofType` must be a type literal" case .erasedToConcreteExistentialInvalidType: "The argument `erasedToConcreteExistential` must be a bool literal" case .erasedInstantiatorUsedWithoutFulfilledByType: - "`ErasedInstantiator` and `NonisolatedErasedInstantiator` require use of the argument `fulfilledByType`" + "`ErasedInstantiator` and `SendableErasedInstantiator` require use of the argument `fulfilledByType`" } } } diff --git a/Tests/SafeDIMacrosTests/InjectableMacroTests.swift b/Tests/SafeDIMacrosTests/InjectableMacroTests.swift index e916bc45..a98c7077 100644 --- a/Tests/SafeDIMacrosTests/InjectableMacroTests.swift +++ b/Tests/SafeDIMacrosTests/InjectableMacroTests.swift @@ -148,7 +148,7 @@ import SafeDICore public struct ExampleService { @Instantiated(fulfilledByType: "LoginViewController") ┬──────────────────────────────────────────────────── - ╰─ 🛑 The argument `fulfilledByType` can not be used on an `Instantiator` or `NonisolatedInstantiator`. Use an `ErasedInstantiator` or `NonisolatedErasedInstantiator` instead + ╰─ 🛑 The argument `fulfilledByType` can not be used on an `Instantiator` or `SendableInstantiator`. Use an `ErasedInstantiator` or `SendableErasedInstantiator` instead let loginViewControllerBuilder: Instantiator } """ @@ -168,7 +168,7 @@ import SafeDICore public struct ExampleService { @Instantiated ┬──────────── - ╰─ 🛑 `ErasedInstantiator` and `NonisolatedErasedInstantiator` require use of the argument `fulfilledByType` + ╰─ 🛑 `ErasedInstantiator` and `SendableErasedInstantiator` require use of the argument `fulfilledByType` let loginViewControllerBuilder: ErasedInstantiator } """ diff --git a/Tests/SafeDITests/NonisolatedErasedInstantiatorTests.swift b/Tests/SafeDITests/SendableErasedInstantiatorTests.swift similarity index 88% rename from Tests/SafeDITests/NonisolatedErasedInstantiatorTests.swift rename to Tests/SafeDITests/SendableErasedInstantiatorTests.swift index 5d8d8f15..be7d2817 100644 --- a/Tests/SafeDITests/NonisolatedErasedInstantiatorTests.swift +++ b/Tests/SafeDITests/SendableErasedInstantiatorTests.swift @@ -22,16 +22,16 @@ import XCTest @testable import SafeDI -final class NonisolatedErasedInstantiatorTests: XCTestCase { +final class SendableErasedInstantiatorTests: XCTestCase { func test_instantiate_returnsNewObjectEachTime() { - let systemUnderTest = NonisolatedErasedInstantiator() { BuiltProduct() } + let systemUnderTest = SendableErasedInstantiator() { BuiltProduct() } let firstBuiltProduct = systemUnderTest.instantiate() let secondBuiltProduct = systemUnderTest.instantiate() XCTAssertFalse(firstBuiltProduct === secondBuiltProduct) } func test_instantiate_withForwardedArgument_returnsNewObjectEachTime() { - let systemUnderTest = NonisolatedErasedInstantiator { id in BuiltProductWithForwardedArgument(id: id) } + let systemUnderTest = SendableErasedInstantiator { id in BuiltProductWithForwardedArgument(id: id) } let id = UUID().uuidString let firstBuiltProduct = systemUnderTest.instantiate(id) let secondBuiltProduct = systemUnderTest.instantiate(id) diff --git a/Tests/SafeDITests/NonisolatedInstantiatorTests.swift b/Tests/SafeDITests/SendableInstantiatorTests.swift similarity index 89% rename from Tests/SafeDITests/NonisolatedInstantiatorTests.swift rename to Tests/SafeDITests/SendableInstantiatorTests.swift index d0bde4d2..4a88d9e0 100644 --- a/Tests/SafeDITests/NonisolatedInstantiatorTests.swift +++ b/Tests/SafeDITests/SendableInstantiatorTests.swift @@ -22,16 +22,16 @@ import XCTest @testable import SafeDI -final class NonisolatedInstantiatorTests: XCTestCase { +final class SendableInstantiatorTests: XCTestCase { func test_instantiate_returnsNewObjectEachTime() { - let systemUnderTest = NonisolatedInstantiator { BuiltProduct() } + let systemUnderTest = SendableInstantiator { BuiltProduct() } let firstBuiltProduct = systemUnderTest.instantiate() let secondBuiltProduct = systemUnderTest.instantiate() XCTAssertFalse(firstBuiltProduct === secondBuiltProduct) } func test_instantiate_withForwardedArgument_returnsNewObjectEachTime() { - let systemUnderTest = NonisolatedInstantiator { id in BuiltProductWithForwardedArgument(id: id) } + let systemUnderTest = SendableInstantiator { id in BuiltProductWithForwardedArgument(id: id) } let id = UUID().uuidString let firstBuiltProduct = systemUnderTest.instantiate(id) let secondBuiltProduct = systemUnderTest.instantiate(id) diff --git a/Tests/SafeDIToolTests/SafeDIToolTests.swift b/Tests/SafeDIToolTests/SafeDIToolTests.swift index 9d41f2d4..418e163b 100644 --- a/Tests/SafeDIToolTests/SafeDIToolTests.swift +++ b/Tests/SafeDIToolTests/SafeDIToolTests.swift @@ -533,7 +533,7 @@ final class SafeDIToolTests: XCTestCase { public convenience init() { let networkService: NetworkService = DefaultNetworkService() let authService: AuthService = DefaultAuthService(networkService: networkService) - @MainActor func __safeDI_loggedInViewControllerBuilder(user: User) -> LoggedInViewController { + func __safeDI_loggedInViewControllerBuilder(user: User) -> LoggedInViewController { LoggedInViewController(user: user, networkService: networkService) } let loggedInViewControllerBuilder = ErasedInstantiator { @@ -647,7 +647,7 @@ final class SafeDIToolTests: XCTestCase { public convenience init() { let networkService: NetworkService = DefaultNetworkService() let authService: AuthService = DefaultAuthService(networkService: networkService) - @MainActor func __safeDI_loggedInViewControllerBuilder(user: User) -> LoggedInViewController { + func __safeDI_loggedInViewControllerBuilder(user: User) -> LoggedInViewController { let userService = UserService(user: user) return LoggedInViewController(user: user, networkService: networkService, userService: userService) } @@ -771,7 +771,7 @@ final class SafeDIToolTests: XCTestCase { public convenience init() { let networkService: NetworkService = DefaultNetworkService() let authService: AuthService = DefaultAuthService(networkService: networkService) - @MainActor func __safeDI_loggedInViewControllerBuilder(userID: String, userName: String) -> LoggedInViewController { + func __safeDI_loggedInViewControllerBuilder(userID: String, userName: String) -> LoggedInViewController { let userService = UserService(userName: userName, userID: userID) return LoggedInViewController(userName: userName, userID: userID, networkService: networkService, userService: userService) } @@ -895,7 +895,7 @@ final class SafeDIToolTests: XCTestCase { public convenience init() { let networkService: NetworkService = DefaultNetworkService() let authService: AuthService = DefaultAuthService(networkService: networkService) - @MainActor func __safeDI_loggedInViewControllerBuilder(userID: String, userName: String) -> LoggedInViewController { + func __safeDI_loggedInViewControllerBuilder(userID: String, userName: String) -> LoggedInViewController { let userService = UserService(userName: userName, userID: userID) return LoggedInViewController(userName: userName, userID: userID, networkService: networkService, userService: userService) } @@ -995,7 +995,7 @@ final class SafeDIToolTests: XCTestCase { extension RootView { public init() { - @MainActor func __safeDI_splashScreenViewBuilder() -> SplashScreenView { + func __safeDI_splashScreenViewBuilder() -> SplashScreenView { SplashScreenView() } let splashScreenViewBuilder = ErasedInstantiator<(), AnyView> { @@ -1109,7 +1109,7 @@ final class SafeDIToolTests: XCTestCase { public convenience init() { let networkService: NetworkService = DefaultNetworkService() let authService: AuthService = DefaultAuthService(networkService: networkService) - @MainActor func __safeDI_loggedInViewControllerBuilder(user: User) -> LoggedInViewController { + func __safeDI_loggedInViewControllerBuilder(user: User) -> LoggedInViewController { let userService = UserService(user: user, networkService: networkService) return LoggedInViewController(user: user, userService: userService) } @@ -1224,8 +1224,8 @@ final class SafeDIToolTests: XCTestCase { public convenience init() { let networkService: NetworkService = DefaultNetworkService() let authService: AuthService = DefaultAuthService(networkService: networkService) - @MainActor func __safeDI_loggedInViewControllerBuilder(user: User) -> LoggedInViewController { - @MainActor func __safeDI_userServiceInstantiator() -> UserService { + func __safeDI_loggedInViewControllerBuilder(user: User) -> LoggedInViewController { + func __safeDI_userServiceInstantiator() -> UserService { UserService(user: user, networkService: networkService) } let userServiceInstantiator = Instantiator(__safeDI_userServiceInstantiator) @@ -1858,7 +1858,7 @@ final class SafeDIToolTests: XCTestCase { """, """ @Instantiable - public final class Recreated {} + public final class Recreated: Sendable {} """, """ @Instantiable @@ -1949,7 +1949,7 @@ final class SafeDIToolTests: XCTestCase { @Instantiable public final class Root { @Instantiated(fulfilledByType: "ChildA") - let childABuilder: NonisolatedErasedInstantiator + let childABuilder: SendableErasedInstantiator @Instantiated let childB: ChildB @Instantiated @@ -1961,7 +1961,7 @@ final class SafeDIToolTests: XCTestCase { public final class Recreated {} """, """ - public protocol ChildAProtocol {} + public protocol ChildAProtocol: Sendable {} @Instantiable public final class ChildA: ChildAProtocol { @Instantiated @@ -2019,7 +2019,7 @@ final class SafeDIToolTests: XCTestCase { extension Root { public convenience init() { - nonisolated func __safeDI_childABuilder(recreated: Recreated) -> ChildA { + @Sendable func __safeDI_childABuilder(recreated: Recreated) -> ChildA { let grandchildA: GrandchildA = { let recreated = Recreated() let greatGrandchild = GreatGrandchild(recreated: recreated) @@ -2031,7 +2031,7 @@ final class SafeDIToolTests: XCTestCase { }() return ChildA(grandchildA: grandchildA, grandchildB: grandchildB, recreated: recreated) } - let childABuilder = NonisolatedErasedInstantiator { + let childABuilder = SendableErasedInstantiator { __safeDI_childABuilder(recreated: $0) } let recreated = Recreated() @@ -2342,7 +2342,7 @@ final class SafeDIToolTests: XCTestCase { public convenience init() { let networkService: NetworkService = DefaultNetworkService() let authService: AuthService = DefaultAuthService(networkService: networkService) - @MainActor func __safeDI_loggedInViewControllerBuilder(user: User) -> LoggedInViewController { + func __safeDI_loggedInViewControllerBuilder(user: User) -> LoggedInViewController { let keyValueStore: KeyValueStore = UserDefaults.instantiate(user: user) return LoggedInViewController(user: user, networkService: networkService, keyValueStore: keyValueStore) } @@ -2361,7 +2361,7 @@ final class SafeDIToolTests: XCTestCase { swiftFileContent: [ """ @Instantiable() - public final class GreatGrandchild {} + public final class GreatGrandchild: Sendable {} """, ], buildDependencyTreeOutput: false @@ -2393,7 +2393,7 @@ final class SafeDIToolTests: XCTestCase { @Instantiable() public final class GrandchildBA { @Instantiated - var greatGrandchildInstantiator: NonisolatedInstantiator + var greatGrandchildInstantiator: SendableInstantiator } """, """ @@ -2402,7 +2402,7 @@ final class SafeDIToolTests: XCTestCase { @Instantiable() public final class GrandchildBB { @Instantiated - greatGrandchildInstantiator: NonisolatedInstantiator + greatGrandchildInstantiator: SendableInstantiator } """, ], @@ -2499,17 +2499,17 @@ final class SafeDIToolTests: XCTestCase { }() let childB: ChildB = { let grandchildBA: GrandchildBA = { - nonisolated func __safeDI_greatGrandchildInstantiator() -> GreatGrandchild { + @Sendable func __safeDI_greatGrandchildInstantiator() -> GreatGrandchild { GreatGrandchild() } - let greatGrandchildInstantiator = NonisolatedInstantiator(__safeDI_greatGrandchildInstantiator) + let greatGrandchildInstantiator = SendableInstantiator(__safeDI_greatGrandchildInstantiator) return GrandchildBA(greatGrandchildInstantiator: greatGrandchildInstantiator) }() let grandchildBB: GrandchildBB = { - nonisolated func __safeDI_greatGrandchildInstantiator() -> GreatGrandchild { + @Sendable func __safeDI_greatGrandchildInstantiator() -> GreatGrandchild { GreatGrandchild() } - let greatGrandchildInstantiator = NonisolatedInstantiator(__safeDI_greatGrandchildInstantiator) + let greatGrandchildInstantiator = SendableInstantiator(__safeDI_greatGrandchildInstantiator) return GrandchildBB(greatGrandchildInstantiator: greatGrandchildInstantiator) }() return ChildB(grandchildBA: grandchildBA, grandchildBB: grandchildBB) @@ -2750,10 +2750,10 @@ final class SafeDIToolTests: XCTestCase { public convenience init() { let networkService: NetworkService = DefaultNetworkService() let authService: AuthService = DefaultAuthService(networkService: networkService) - @MainActor func __safeDI_loggedInViewControllerBuilder(userManager: UserManager) -> LoggedInViewController { - @MainActor func __safeDI_profileViewControllerBuilder() -> ProfileViewController { + func __safeDI_loggedInViewControllerBuilder(userManager: UserManager) -> LoggedInViewController { + func __safeDI_profileViewControllerBuilder() -> ProfileViewController { let userVendor: UserVendor = userManager - @MainActor func __safeDI_editProfileViewControllerBuilder() -> EditProfileViewController { + func __safeDI_editProfileViewControllerBuilder() -> EditProfileViewController { EditProfileViewController(userVendor: userVendor, userManager: userManager) } let editProfileViewControllerBuilder = Instantiator(__safeDI_editProfileViewControllerBuilder) @@ -2815,8 +2815,8 @@ final class SafeDIToolTests: XCTestCase { extension Root { public convenience init() { - @MainActor func __safeDI_childBuilder(iterator: IndexingIterator>) -> Child { - @MainActor func __safeDI_grandchildBuilder() -> Grandchild { + func __safeDI_childBuilder(iterator: IndexingIterator>) -> Child { + func __safeDI_grandchildBuilder() -> Grandchild { let anyIterator = AnyIterator(iterator) return Grandchild(anyIterator: anyIterator) } @@ -2966,11 +2966,11 @@ final class SafeDIToolTests: XCTestCase { public convenience init() { let networkService: NetworkService = DefaultNetworkService() let authService: AuthService = DefaultAuthService(networkService: networkService) - @MainActor func __safeDI_loggedInViewControllerBuilder(userManager: UserManager) -> LoggedInViewController { + func __safeDI_loggedInViewControllerBuilder(userManager: UserManager) -> LoggedInViewController { let userNetworkService: NetworkService = networkService - @MainActor func __safeDI_profileViewControllerBuilder() -> ProfileViewController { + func __safeDI_profileViewControllerBuilder() -> ProfileViewController { let userVendor: UserVendor = userManager - @MainActor func __safeDI_editProfileViewControllerBuilder() -> EditProfileViewController { + func __safeDI_editProfileViewControllerBuilder() -> EditProfileViewController { EditProfileViewController(userVendor: userVendor, userManager: userManager, userNetworkService: userNetworkService) } let editProfileViewControllerBuilder = Instantiator(__safeDI_editProfileViewControllerBuilder) @@ -3273,10 +3273,10 @@ final class SafeDIToolTests: XCTestCase { public convenience init() { let networkService: NetworkService = DefaultNetworkService() let authService: AuthService = DefaultAuthService(networkService: networkService) - @MainActor func __safeDI_loggedInViewControllerBuilder(userManager: UserManager) -> LoggedInViewController { + func __safeDI_loggedInViewControllerBuilder(userManager: UserManager) -> LoggedInViewController { let userVendor: UserVendor = userManager - @MainActor func __safeDI_profileViewControllerBuilder() -> ProfileViewController { - @MainActor func __safeDI_editProfileViewControllerBuilder() -> EditProfileViewController { + func __safeDI_profileViewControllerBuilder() -> ProfileViewController { + func __safeDI_editProfileViewControllerBuilder() -> EditProfileViewController { EditProfileViewController(userVendor: userVendor, userManager: userManager) } let editProfileViewControllerBuilder = Instantiator(__safeDI_editProfileViewControllerBuilder) @@ -3420,9 +3420,9 @@ final class SafeDIToolTests: XCTestCase { public convenience init() { let networkService: NetworkService = DefaultNetworkService() let authService: AuthService = DefaultAuthService(networkService: networkService) - @MainActor func __safeDI_loggedInViewControllerBuilder(userManager: UserManager) -> LoggedInViewController { - @MainActor func __safeDI_profileViewControllerBuilder() -> ProfileViewController { - @MainActor func __safeDI_editProfileViewControllerBuilder() -> EditProfileViewController { + func __safeDI_loggedInViewControllerBuilder(userManager: UserManager) -> LoggedInViewController { + func __safeDI_profileViewControllerBuilder() -> ProfileViewController { + func __safeDI_editProfileViewControllerBuilder() -> EditProfileViewController { let userVendor: UserVendor = userManager return EditProfileViewController(userVendor: userVendor, userManager: userManager) } @@ -3909,7 +3909,7 @@ final class SafeDIToolTests: XCTestCase { extension Root { public convenience init() { - @MainActor func __safeDI_childBuilder() -> Child { + func __safeDI_childBuilder() -> Child { Child() } let childBuilder: Instantiator? = Instantiator(__safeDI_childBuilder) @@ -3964,9 +3964,9 @@ final class SafeDIToolTests: XCTestCase { extension Root { public init() { - @MainActor func __safeDI_aBuilder() -> A { - @MainActor func __safeDI_bBuilder() -> B { - @MainActor func __safeDI_cBuilder() -> C { + func __safeDI_aBuilder() -> A { + func __safeDI_bBuilder() -> B { + func __safeDI_cBuilder() -> C { let aBuilder = Instantiator(__safeDI_aBuilder) return C(aBuilder: aBuilder) } @@ -4030,7 +4030,7 @@ final class SafeDIToolTests: XCTestCase { public init() { let a: A = { let b: B = { - @MainActor func __safeDI_cBuilder() -> C { + func __safeDI_cBuilder() -> C { let a = A(b: b) return C(a: a) } @@ -4077,7 +4077,7 @@ final class SafeDIToolTests: XCTestCase { extension Root { public init() { let a: A = { - @MainActor func __safeDI_aBuilder() -> A { + func __safeDI_aBuilder() -> A { let aBuilder = Instantiator(__safeDI_aBuilder) return A(aBuilder: aBuilder) } @@ -4123,7 +4123,7 @@ final class SafeDIToolTests: XCTestCase { extension Root { public init() { - @MainActor func __safeDI_aBuilder(context: String) -> A { + func __safeDI_aBuilder(context: String) -> A { let aBuilder = Instantiator { __safeDI_aBuilder(context: $0) }