Skip to content

Conversation

@gottesmm
Copy link
Contributor

@gottesmm gottesmm commented Feb 7, 2026

NOTE: This is a draft since I am just testing this out with the source compat suite. I will add more tests/etc if it looks good.


Fixes rdar://169803154

Previously, we were emitting an unknown pattern error in code like:

@MainActor
class MainActorIsolatedKlass {
  init() {
    Task.detached { @MainActor in
      _ = self
      for try await x in E.seq {
      }
    }
  }
}

enum E {
  static var seq: some AsyncSequence<Float, Error> {
    AsyncThrowingStream(Float.self) { $0.finish() }
  }
}

The issue was that the closure was considered non-Sendable despite being @mainactor due to the try await in it. Investigation revealed an inconsistency between the constraint solver and getClosureIsolation:

  1. In the constraint solver, we were only honoring explicit global actor isolation for non-async functions, which caused us to not infer that the closure should have been Sendable despite the try await.

  2. Later getClosureIsolation did the correct thing and we labeled the closure as having global actor isolation, but that did not impact the actual type of the closure being Sendable at the SIL level.

The result was a non-Sendable main actor isolated closure.

This commit removes the restriction that prevented honoring explicit global actor isolation for async closures, making the constraint solver consistent with getClosureIsolation.

…nstraint solver

Fixes rdar://169803154

Previously, we were emitting an unknown pattern error in code like:

```
@mainactor
class MainActorIsolatedKlass {
  init() {
    Task.detached { @mainactor in
      _ = self
      for try await x in E.seq {
      }
    }
  }
}

enum E {
  static var seq: some AsyncSequence<Float, Error> {
    AsyncThrowingStream(Float.self) { $0.finish() }
  }
}
```

The issue was that the closure was considered non-Sendable despite being
@mainactor due to the `try await` in it. Investigation revealed an
inconsistency between the constraint solver and getClosureIsolation:

1. In the constraint solver, we were only honoring explicit global actor
   isolation for non-async functions, which caused us to not infer that
   the closure should have been Sendable despite the try await.

2. Later getClosureIsolation did the correct thing and we labeled the
   closure as having global actor isolation, but that did not impact the
   actual type of the closure being Sendable at the SIL level.

The result was a non-Sendable main actor isolated closure.

This commit removes the restriction that prevented honoring explicit
global actor isolation for async closures, making the constraint solver
consistent with getClosureIsolation.
@gottesmm gottesmm requested review from hborla and xedin as code owners February 7, 2026 20:54
@gottesmm
Copy link
Contributor Author

gottesmm commented Feb 7, 2026

@swift-ci test source compatibility suite

@gottesmm
Copy link
Contributor Author

gottesmm commented Feb 7, 2026

@swift-ci test source compatibility

@xedin
Copy link
Contributor

xedin commented Feb 8, 2026

Release failure is unrelated, it timed out during cleanup.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants