Description
Hi, by trying using Swinject on a project I am working on migrating to Swift 6, I encountered an issue caused by the a new behavior introduced by SE-0352 when using Swift 6.
Here the issue, that I tried in form of a test in ContainerTests_Arguments
test suite :
This test pass when using Swift 5, but when using the new Swift 6 language mode (done with SWIFT_VERSION = 6 in build settings) the test no longer pass, and we got a nil
from the resolve call.
func testContainerArgumentsWorksWithExistentials() throws {
container.register(Person.self) { (r, animal: Animal) in PetOwner(pet: animal) }
let animal: Animal = Cat(name: "cat")
let person = container.resolve(Person.self, argument: animal)
let petOwner = try XCTUnwrap(person as? PetOwner) // error: XCTUnwrap failed: expected non-nil value of type "PetOwner"
let cat = try XCTUnwrap(petOwner.pet as? Cat)
XCTAssertEqual(cat.name, "cat")
}
And here is what is printed in the console:
Swinject: Resolution failed. Expected registration:
{ Service: Person, Factory: (Resolver, Cat) -> Person }
Available registrations:
{ Service: Person, Factory: (Resolver, Animal) -> Person, ObjectScope: graph }
After some investigation, this behavior change from Swift is documented in the section ""Losing" constraints when type-erasing resulting values" of SE-0352.
The solution is also provided by the proposal: opting out from this new implicit existential opening with as any P
/ as! any P
. So in my example replacing the line resolving the person with this line makes the test pass in Swift 6:
let person = container.resolve(Person.self, argument: animal as Animal)
I didn't find another way to fix this issue, but at least I was able to understand what was happening. I am not sure what's the next step for this issue, maybe at least more documentation warning about this issue ?
You can find the project with some changes on top of main to make it compile with Swift 6 here: https://github.com/alexandre-pod/Swinject/tree/swift-6-support
(This was tried on Xcode 16.0 beta 3)