Why do almost all AsyncIterators rethrow?

AsyncStream.Iterator.next and TaskGroup.Iterator.next don't rethrow.

Instead, to get

async throws -> Element?

instead of

async -> Element?

, you need the throwing variants. (AsyncThrowingStream and ThrowingTaskGroup).


But the rest of the AsyncIteratorProtocol adopters in the standard library, while also having throwing and non-throwing variants, use this pair of signatures instead:

async rethrows -> Element?
async throws -> Element?

1. When does that rethrows get used?
2. Why the inconsistency?


I was looking at the "AnyAsyncSequence" thread, and thinking that, at this point, we're always working with "some AsyncNonThrowingSequence<Element>" or "some AsyncThrowingSequence<Element>":

public protocol AsyncNonThrowingSequence<Element>: AsyncSequence
where AsyncIterator: Swift.AsyncIterator { }

public protocol AsyncIterator<Element>: AsyncIteratorProtocol {
  associatedtype Element
  mutating func next() async -> Element?
}

public protocol AsyncThrowingSequence<Element>: AsyncSequence
where AsyncIterator: AsyncThrowingIterator { }

public protocol AsyncThrowingIterator<Element>: AsyncIteratorProtocol {
  associatedtype Element
  mutating func next() async throws -> Element?
}

…but while that idea works with Streams…

extension AsyncStream: AsyncNonThrowingSequence { }
extension AsyncStream.Iterator: AsyncIterator { }

extension AsyncThrowingStream: AsyncThrowingSequence { }
extension AsyncThrowingStream.Iterator: AsyncThrowingIterator { }

…it doesn't work with anything else, because rethrows doesn't propagate into the type system.