Skip to content

Commit 0c6c369

Browse files
committed
[Concurrency] Apply nonisolated(unsafe) to iterator variables for
async for-in loops. Async iterators are not `Sendable`; they're only meant to be used from the isolation domain that creates them. But the `next()` method runs on the generic executor, so calling it from an actor-isolated context passes non-`Sendable` state across the isolation boundary. `next()` should inherit the isolation of the caller, but for now, use the opt out.
1 parent 76ae065 commit 0c6c369

File tree

2 files changed

+19
-0
lines changed

2 files changed

+19
-0
lines changed

lib/Sema/CSGen.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4516,6 +4516,19 @@ generateForEachStmtConstraints(ConstraintSystem &cs, DeclContext *dc,
45164516
sequenceExpr->getStartLoc(), ctx.getIdentifier(name), dc);
45174517
makeIteratorVar->setImplicit();
45184518

4519+
// FIXME: Apply `nonisolated(unsafe)` to async iterators.
4520+
//
4521+
// Async iterators are not `Sendable`; they're only meant to be used from
4522+
// the isolation domain that creates them. But the `next()` method runs on
4523+
// the generic executor, so calling it from an actor-isolated context passes
4524+
// non-`Sendable` state across the isolation boundary. `next()` should
4525+
// inherit the isolation of the caller, but for now, use the opt out.
4526+
if (isAsync) {
4527+
auto *nonisolated = new (ctx)
4528+
NonisolatedAttr(/*unsafe=*/true, /*implicit=*/true);
4529+
makeIteratorVar->getAttrs().add(nonisolated);
4530+
}
4531+
45194532
// First, let's form a call from sequence to `.makeIterator()` and save
45204533
// that in a special variable which is going to be used by SILGen.
45214534
{

test/Concurrency/experimental_feature_strictconcurrency.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,4 +96,10 @@ func iterate(stream: AsyncStream<Int>) async {
9696
while let element = await it.next() {
9797
print(element)
9898
}
99+
100+
// expected-region-isolation-warning@+2 {{passing argument of non-sendable type 'AsyncStream<Int>.Iterator' from main actor-isolated context to nonisolated context at this call site could yield a race with accesses later in this function}}
101+
// expected-region-isolation-note@+1 {{access here could race}}
102+
for await x in stream {
103+
print(x)
104+
}
99105
}

0 commit comments

Comments
 (0)