Why does my AsyncSequence with no non-isolated next() function crash on iOS 18.1?

I recently rewrote an AsyncSequence, whose decl now looks roughly like the following:

public struct AnyAsyncSequence<Element, Failure>: AsyncSequence, Sendable, SendableMetatype where Failure: Error {

    public struct Iterator: AsyncIteratorProtocol, SendableMetatype {

        public mutating func next(
            isolation actor: isolated (any Actor)?
        ) async throws(Failure) -> Element? {
            ...
        }

    }

}

Originally, it had a public func next() async -> Element? impl (and no Failure case).

However, the removal of the next() function with that decl causes the app to crash at launch on the iOS 18.1 simulator in dyld. According to the person who reported this issue, an LLM informed them that the binary now wants to load the symbol sScIsE4next7ElementQzSgyYa7FailureQzYKF, aka (extension in Swift):Swift.AsyncIteratorProtocol.next() async throws(A.Failure) -> A.Element?, which is not present in the iOS 18 simulator.

This came as a surprise to me; firstly that it's not present, and secondly, that it's looking for a version that throws a Failure case, when the non-isolated next() decl does not include Failure even after Failure was added to the stdlib.

I've fixed this by adding this decl to my AsyncSequence: public mutating func next() async throws(Failure) -> Element? but I'm wondering if I should also be adding a next that throws or something to fully comply with the protocol requirement?

One other interesting detail is that it seems like some code in my codebase was, according to Xcode's index, directly calling this non-existent non-isolated-typed-throws variant.

1 Like