Skip to content

Commit 377b527

Browse files
committed
[Concurrency] Async{Throwing}Stream.init(unfolding:) should accept a
`@Sendable` closure.
1 parent f78690b commit 377b527

File tree

3 files changed

+88
-50
lines changed

3 files changed

+88
-50
lines changed

stdlib/public/Concurrency/AsyncStream.swift

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -330,8 +330,20 @@ public struct AsyncStream<Element> {
330330
/// }
331331
///
332332
///
333+
@_alwaysEmitIntoClient
333334
public init(
334-
unfolding produce: @escaping () async -> Element?,
335+
unfolding produce: @escaping @Sendable () async -> Element?,
336+
onCancel: (@Sendable () -> Void)? = nil
337+
) {
338+
self.init(
339+
unfolding: produce as () async -> Element?,
340+
onCancel: onCancel
341+
)
342+
}
343+
344+
@usableFromInline
345+
internal init(
346+
unfolding produce: @escaping () async -> Element?,
335347
onCancel: (@Sendable () -> Void)? = nil
336348
) {
337349
let storage: _AsyncStreamCriticalStorage<Optional<() async -> Element?>>

stdlib/public/Concurrency/AsyncThrowingStream.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,17 @@ public struct AsyncThrowingStream<Element, Failure: Error> {
369369
/// print(error)
370370
/// }
371371
///
372+
@_alwaysEmitIntoClient
372373
public init(
374+
unfolding produce: @escaping @Sendable () async throws -> Element?
375+
) where Failure == Error {
376+
self.init(
377+
unfolding: produce as () async throws -> Element?
378+
)
379+
}
380+
381+
@usableFromInline
382+
internal init(
373383
unfolding produce: @escaping () async throws -> Element?
374384
) where Failure == Error {
375385
let storage: _AsyncStreamCriticalStorage<Optional<() async throws -> Element?>>

test/Concurrency/Runtime/async_stream.swift

Lines changed: 65 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// RUN: %target-typecheck-verify-swift -strict-concurrency=complete -disable-availability-checking -parse-as-library
12
// RUN: %target-run-simple-swift( -Xfrontend -disable-availability-checking -parse-as-library)
23

34
// REQUIRES: concurrency
@@ -15,7 +16,22 @@ struct SomeError: Error, Equatable {
1516
var value = Int.random(in: 0..<100)
1617
}
1718

18-
var tests = TestSuite("AsyncStream")
19+
class NotSendable {}
20+
21+
@MainActor func testWarnings() {
22+
var x = 0
23+
_ = AsyncStream {
24+
x += 1 // expected-warning {{mutation of captured var 'x' in concurrently-executing code; this is an error in the Swift 6 language mode}}
25+
return 0
26+
}
27+
28+
_ = AsyncThrowingStream {
29+
x += 1 // expected-warning {{mutation of captured var 'x' in concurrently-executing code; this is an error in the Swift 6 language mode}}
30+
return
31+
}
32+
}
33+
34+
@MainActor var tests = TestSuite("AsyncStream")
1935

2036
@main struct Main {
2137
static func main() async {
@@ -29,7 +45,7 @@ var tests = TestSuite("AsyncStream")
2945
continuation.yield("hello")
3046

3147
var iterator = stream.makeAsyncIterator()
32-
expectEqual(await iterator.next(), "hello")
48+
expectEqual(await iterator.next(isolation: #isolation), "hello")
3349
}
3450

3551
tests.test("throwing factory method") {
@@ -38,7 +54,7 @@ var tests = TestSuite("AsyncStream")
3854

3955
var iterator = stream.makeAsyncIterator()
4056
do {
41-
expectEqual(try await iterator.next(), "hello")
57+
expectEqual(try await iterator.next(isolation: #isolation), "hello")
4258
} catch {
4359
expectUnreachable("unexpected error thrown")
4460
}
@@ -61,7 +77,7 @@ var tests = TestSuite("AsyncStream")
6177
continuation.yield("hello")
6278
}
6379
var iterator = series.makeAsyncIterator()
64-
expectEqual(await iterator.next(), "hello")
80+
expectEqual(await iterator.next(isolation: #isolation), "hello")
6581
}
6682

6783
tests.test("yield with awaiting next throwing") {
@@ -70,7 +86,7 @@ var tests = TestSuite("AsyncStream")
7086
}
7187
var iterator = series.makeAsyncIterator()
7288
do {
73-
expectEqual(try await iterator.next(), "hello")
89+
expectEqual(try await iterator.next(isolation: #isolation), "hello")
7490
} catch {
7591
expectUnreachable("unexpected error thrown")
7692
}
@@ -82,8 +98,8 @@ var tests = TestSuite("AsyncStream")
8298
continuation.yield("world")
8399
}
84100
var iterator = series.makeAsyncIterator()
85-
expectEqual(await iterator.next(), "hello")
86-
expectEqual(await iterator.next(), "world")
101+
expectEqual(await iterator.next(isolation: #isolation), "hello")
102+
expectEqual(await iterator.next(isolation: #isolation), "world")
87103
}
88104

89105
tests.test("yield with awaiting next 2 throwing") {
@@ -93,8 +109,8 @@ var tests = TestSuite("AsyncStream")
93109
}
94110
var iterator = series.makeAsyncIterator()
95111
do {
96-
expectEqual(try await iterator.next(), "hello")
97-
expectEqual(try await iterator.next(), "world")
112+
expectEqual(try await iterator.next(isolation: #isolation), "hello")
113+
expectEqual(try await iterator.next(isolation: #isolation), "world")
98114
} catch {
99115
expectUnreachable("unexpected error thrown")
100116
}
@@ -107,9 +123,9 @@ var tests = TestSuite("AsyncStream")
107123
continuation.finish()
108124
}
109125
var iterator = series.makeAsyncIterator()
110-
expectEqual(await iterator.next(), "hello")
111-
expectEqual(await iterator.next(), "world")
112-
expectEqual(await iterator.next(), nil)
126+
expectEqual(await iterator.next(isolation: #isolation), "hello")
127+
expectEqual(await iterator.next(isolation: #isolation), "world")
128+
expectEqual(await iterator.next(isolation: #isolation), nil)
113129
}
114130

115131
tests.test("yield with awaiting next 2 and finish throwing") {
@@ -120,9 +136,9 @@ var tests = TestSuite("AsyncStream")
120136
}
121137
var iterator = series.makeAsyncIterator()
122138
do {
123-
expectEqual(try await iterator.next(), "hello")
124-
expectEqual(try await iterator.next(), "world")
125-
expectEqual(try await iterator.next(), nil)
139+
expectEqual(try await iterator.next(isolation: #isolation), "hello")
140+
expectEqual(try await iterator.next(isolation: #isolation), "world")
141+
expectEqual(try await iterator.next(isolation: #isolation), nil)
126142
} catch {
127143
expectUnreachable("unexpected error thrown")
128144
}
@@ -137,9 +153,9 @@ var tests = TestSuite("AsyncStream")
137153
}
138154
var iterator = series.makeAsyncIterator()
139155
do {
140-
expectEqual(try await iterator.next(), "hello")
141-
expectEqual(try await iterator.next(), "world")
142-
_ = try await iterator.next()
156+
expectEqual(try await iterator.next(isolation: #isolation), "hello")
157+
expectEqual(try await iterator.next(isolation: #isolation), "world")
158+
_ = try await iterator.next(isolation: #isolation)
143159
expectUnreachable("expected thrown error")
144160
} catch {
145161
if let failure = error as? SomeError {
@@ -173,7 +189,7 @@ var tests = TestSuite("AsyncStream")
173189
}
174190
}
175191
var iterator = series.makeAsyncIterator()
176-
expectEqual(await iterator.next(), "hello")
192+
expectEqual(await iterator.next(isolation: #isolation), "hello")
177193
}
178194

179195
tests.test("yield with awaiting next detached throwing") {
@@ -184,7 +200,7 @@ var tests = TestSuite("AsyncStream")
184200
}
185201
var iterator = series.makeAsyncIterator()
186202
do {
187-
expectEqual(try await iterator.next(), "hello")
203+
expectEqual(try await iterator.next(isolation: #isolation), "hello")
188204
} catch {
189205
expectUnreachable("unexpected error thrown")
190206
}
@@ -198,8 +214,8 @@ var tests = TestSuite("AsyncStream")
198214
}
199215
}
200216
var iterator = series.makeAsyncIterator()
201-
expectEqual(await iterator.next(), "hello")
202-
expectEqual(await iterator.next(), "world")
217+
expectEqual(await iterator.next(isolation: #isolation), "hello")
218+
expectEqual(await iterator.next(isolation: #isolation), "world")
203219
}
204220

205221
tests.test("yield with awaiting next 2 detached throwing") {
@@ -211,8 +227,8 @@ var tests = TestSuite("AsyncStream")
211227
}
212228
var iterator = series.makeAsyncIterator()
213229
do {
214-
expectEqual(try await iterator.next(), "hello")
215-
expectEqual(try await iterator.next(), "world")
230+
expectEqual(try await iterator.next(isolation: #isolation), "hello")
231+
expectEqual(try await iterator.next(isolation: #isolation), "world")
216232
} catch {
217233
expectUnreachable("unexpected error thrown")
218234
}
@@ -227,9 +243,9 @@ var tests = TestSuite("AsyncStream")
227243
}
228244
}
229245
var iterator = series.makeAsyncIterator()
230-
expectEqual(await iterator.next(), "hello")
231-
expectEqual(await iterator.next(), "world")
232-
expectEqual(await iterator.next(), nil)
246+
expectEqual(await iterator.next(isolation: #isolation), "hello")
247+
expectEqual(await iterator.next(isolation: #isolation), "world")
248+
expectEqual(await iterator.next(isolation: #isolation), nil)
233249
}
234250

235251
tests.test("yield with awaiting next 2 and finish detached throwing") {
@@ -242,9 +258,9 @@ var tests = TestSuite("AsyncStream")
242258
}
243259
var iterator = series.makeAsyncIterator()
244260
do {
245-
expectEqual(try await iterator.next(), "hello")
246-
expectEqual(try await iterator.next(), "world")
247-
expectEqual(try await iterator.next(), nil)
261+
expectEqual(try await iterator.next(isolation: #isolation), "hello")
262+
expectEqual(try await iterator.next(isolation: #isolation), "world")
263+
expectEqual(try await iterator.next(isolation: #isolation), nil)
248264
} catch {
249265
expectUnreachable("unexpected error thrown")
250266
}
@@ -261,9 +277,9 @@ var tests = TestSuite("AsyncStream")
261277
}
262278
var iterator = series.makeAsyncIterator()
263279
do {
264-
expectEqual(try await iterator.next(), "hello")
265-
expectEqual(try await iterator.next(), "world")
266-
_ = try await iterator.next()
280+
expectEqual(try await iterator.next(isolation: #isolation), "hello")
281+
expectEqual(try await iterator.next(isolation: #isolation), "world")
282+
_ = try await iterator.next(isolation: #isolation)
267283
expectUnreachable("expected thrown error")
268284
} catch {
269285
if let failure = error as? SomeError {
@@ -284,10 +300,10 @@ var tests = TestSuite("AsyncStream")
284300
}
285301
}
286302
var iterator = series.makeAsyncIterator()
287-
expectEqual(await iterator.next(), "hello")
288-
expectEqual(await iterator.next(), "world")
289-
expectEqual(await iterator.next(), nil)
290-
expectEqual(await iterator.next(), nil)
303+
expectEqual(await iterator.next(isolation: #isolation), "hello")
304+
expectEqual(await iterator.next(isolation: #isolation), "world")
305+
expectEqual(await iterator.next(isolation: #isolation), nil)
306+
expectEqual(await iterator.next(isolation: #isolation), nil)
291307
}
292308

293309
tests.test("yield with awaiting next 2 and finish detached with value after finish throwing") {
@@ -301,10 +317,10 @@ var tests = TestSuite("AsyncStream")
301317
}
302318
var iterator = series.makeAsyncIterator()
303319
do {
304-
expectEqual(try await iterator.next(), "hello")
305-
expectEqual(try await iterator.next(), "world")
306-
expectEqual(try await iterator.next(), nil)
307-
expectEqual(try await iterator.next(), nil)
320+
expectEqual(try await iterator.next(isolation: #isolation), "hello")
321+
expectEqual(try await iterator.next(isolation: #isolation), "world")
322+
expectEqual(try await iterator.next(isolation: #isolation), nil)
323+
expectEqual(try await iterator.next(isolation: #isolation), nil)
308324
} catch {
309325
expectUnreachable("unexpected error thrown")
310326
}
@@ -322,10 +338,10 @@ var tests = TestSuite("AsyncStream")
322338
}
323339
var iterator = series.makeAsyncIterator()
324340
do {
325-
expectEqual(try await iterator.next(), "hello")
326-
expectEqual(try await iterator.next(), "world")
327-
expectEqual(try await iterator.next(), nil)
328-
expectEqual(try await iterator.next(), nil)
341+
expectEqual(try await iterator.next(isolation: #isolation), "hello")
342+
expectEqual(try await iterator.next(isolation: #isolation), "world")
343+
expectEqual(try await iterator.next(isolation: #isolation), nil)
344+
expectEqual(try await iterator.next(isolation: #isolation), nil)
329345
} catch {
330346
expectUnreachable("unexpected error thrown")
331347
}
@@ -341,10 +357,10 @@ var tests = TestSuite("AsyncStream")
341357
}
342358
var iterator = series.makeAsyncIterator()
343359
do {
344-
expectEqual(try await iterator.next(), "hello")
345-
expectEqual(try await iterator.next(), "world")
346-
expectEqual(try await iterator.next(), nil)
347-
expectEqual(try await iterator.next(), nil)
360+
expectEqual(try await iterator.next(isolation: #isolation), "hello")
361+
expectEqual(try await iterator.next(isolation: #isolation), "world")
362+
expectEqual(try await iterator.next(isolation: #isolation), nil)
363+
expectEqual(try await iterator.next(isolation: #isolation), nil)
348364
} catch {
349365
expectUnreachable("unexpected error thrown")
350366
}

0 commit comments

Comments
 (0)