Skip to content

Type inference issues in __allTests__FooTests when using @MainActor #7268

Open
@p4checo

Description

Description

While working in the ReactiveSwift port of The Composable Architecture, more specifically ensuring Linux support, the swift test calls started failing on the generated __allTests__FooTests properties as can be seen below.

Relevant CI run here (from ReactiveCocoa/reactiveswift-composable-architecture#58)

/home/runner/work/reactiveswift-composable-architecture/reactiveswift-composable-architecture/.build/x86_64-unknown-linux-gnu/debug/reactiveswift-composable-architecturePackageTests.derived/ComposableArchitectureTests.swift:227:29: error: cannot convert value of type '[Any]' to expected argument type '[(String, (XCTestCase) -> () -> Void)]'
        testCase(StoreTests.__allTests__StoreTests),
                            ^

After some investigation I was able to narrow down the problem to the use of @MainActor on the test suites, which are used on the "problematic" test suites. I then proceeded to create some minimal examples that replicate the issue.

As they are, the following error is triggered:

Heterogeneous collection literal could only be inferred to '[Any]'; add explicit type annotation if this is intentional
Insert ' as [Any]'

If we uncomment the commented lines, the collection literal is correctly inferred to type [(String, (DummyTests) -> @MainActor () throws -> ())], but even then I'm not sure if it will work as the expected type appears to be[(String, (XCTestCase) -> () throws -> Void)] which doesn't have @MainActor, right?

That means perhaps this means @MainActor is simply not supported yet as it will require new overloads/wrappers to deal with @MainActor annotated tests, and possibly will also involve the codegen in SPM.

For now I will probably disable these tests in Linux, but it would be nice to have them included. Thanks! 🙏🏼

Demo

fileprivate extension DummyTests {
    static let __allTests__DummyTests = [
        ("testNormal", testNormal),
        ("testNormalThrows", testNormalThrows),

        ("testAsync", asyncTest(testAsync)),
        ("testAsyncThrows", asyncTest(testAsyncThrows)),

        ("testMainActor", testMainActor),
//        ("testMainActorThrows", testMainActorThrows), // if we uncomment this one it infers correctly

        ("testMainActorAsync", asyncTest(testMainActorAsync)),
        ("testMainActorAsyncThrows", asyncTest(testMainActorAsyncThrows)),
    ]
}

fileprivate extension MainActorDummyTests {
    static let __allTests__MainActorDummyTests = [
        ("testNormal", testNormal),
//        ("testNormalThrows", testNormalThrows), // if we uncomment this one it infers correctly

        ("testAsync", asyncTest(testAsync)),
        ("testAsyncThrows", asyncTest(testAsyncThrows)),
    ]
}

final class DummyTests: XCTestCase {

    func testNormal() {}
    func testNormalThrows() throws {}

    func testAsync() async {}
    func testAsyncThrows() async throws {}

    @MainActor func testMainActor() {}
    @MainActor func testMainActorThrows() throws {}

    @MainActor func testMainActorAsync() async {}
    @MainActor func testMainActorAsyncThrows() async throws {}
}

@MainActor
final class MainActorDummyTests: XCTestCase {

    func testNormal() {}
    func testNormalThrows() throws {}

    func testAsync() async {}
    func testAsyncThrows() async throws {}
}

Environment

  • Swift 5.7
  • Ubuntu Linux 20.04 and macOS 12.6 / Xcode 14.1 (14B47b)

Metadata

Assignees

No one assigned

    Labels

    swift testChanges impacting `swift test` tool

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions