@preconcurrency not suppressing errors of async getters with transitive dependencies

When using @preconcurrency to suppress Sendable-related errors from a module not yet updated to use strict concurrency checking, calls to get async getters of non-Sendable values don't have suppressed errors if there's a transitive dependency on a type from another module which isn't itself imported using @preconcurrency.

So in Module A I have:

public class MyNonSendableResult {
    public init() {}
}

I use this type in Module B, which depends on Module A:

import ModuleA

public final class MyDependency {
    public func foo() async -> MyNonSendableResult {
        // ...
    }

    public var bar: MyNonSendableResult {
        get async throws {
            // ...
        }
    }
}

And finally, in Module C I use the type from Module B, trying to suppress the errors with @preconcurrency:

@preconcurrency import ModuleB

@MainActor
public final class TestClass {

    let dependency: MyDependency

    init(dependency: MyDependency) {
        self. dependency = dependency
    }

    @MainActor
    public func doThing() async {
        await dependency.foo() // ✅ This works fine.
        try? await dependency.bar // ❌ error: Non-Sendable type 'MyNonSendableResult' of nonisolated property 'bar' cannot be sent to main actor-isolated context 
    }
}

While this works for foo(), it surprisingly fails for bar. I'm not entirely sure if this is a bug or expected behavior. Thoughts?


FWIW: adding a @preconcurrency import ModuleA in Module C's code removes the error, but it's obviously extremely fragile as I'd need to manually track the dependencies of Module B in Module C.

1 Like