-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[6.0][sending] Add support for Task.init and friends and TaskGroup and friends to take sending closures #74608
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@swift-ci test |
Original: #74239 |
feb1508
to
1e0aa66
Compare
@swift-ci test |
…uming parameter The reason why I am doing this is that: 1. We don't support no escaping closure parameters today and would like to leave the design space open. 2. These closures are bitwise copyable/trivial so marking them as specifically consuming doesn't really make sense. (cherry picked from commit 4d7af7b)
…now inferred to be nonisolated. Consider the following piece of code and what the isolation is of the closure literal passed to doSomething(): ```swift func doSomething(_ f: sending () -> ()) { ... } @MyCustomActor func foo() async { doSomething { // What is the isolation here? } } ``` In this case, the isolation of the closure is @MyCustomActor. This is because non-Sendable closures are by default isolated to their current context (in this case @MyCustomActor since foo is @MyCustomActor isolated). This is a problem since 1. Our closure is a synchronous function that does not have the ability to hop to MyCustomActor to run said code. This could result in a concurrency hole caused by running the closure in doSomething() without hopping to MyCustomActor's executor. 2. In Region Based Isolation, a closure that is actor isolated cannot be sent, so we would immediately hit a region isolation error. To fix this issue, by default, if a closure literal is passed as a sending parameter, we make its isolation nonisolated. This ensures that it is disconnected and can be transferred safely. In the case of an async closure literal, we follow the same semantics, but we add an additional wrinkle: we keep support of inheritActorIsolation. If one marks an async closure literal with inheritActorIsolation, we allow for it to be passed as a sendable parameter since it is actually Sendable under the hood. (cherry picked from commit 3f39bdc)
…endable function. We view the conversion from a Sendable to a non-Sendable function via convert function to produce a new fresh sendable value. We should squelch that error. (cherry picked from commit b786c60)
…properly mark actor isolated async closures passed to an inheritActorContext argument as being Sendable. The reason why I am fixing this is that otherwise, we get a warning when one creates an actor isolated closure and pass it into a task, e.x.: ```swift @mainactor func test() { // We would get a warning on the closure below saying that we are sending // a closure that is MainActor isolated. Task { ... } } ``` (cherry picked from commit f781ad3)
… obsolete in swift 6. These APIs remained to preserve source compatibility during bringup. We do not want them used in swift 6 mode... so deprecate in swift 5 and obsolete in swift 6. (cherry picked from commit b541e02)
There is only one call site of this helper function, so we are not gaining any flexibility by doing this. It only makes it harder to reason about what the function actually does without providing any benefit. I am doing this before I make in the next commit an actual semantic changing commit to ease review. (cherry picked from commit ca6cde6)
…g DeclContexts. Without this, we were hitting weird behaviors in flow_isolation.swift only when compiling in Swift 5 mode. Consider the following example: ``` func fakeTask(@_inheritActorContext _ x: sending @escaping () async -> ()) {} actor MyActor { var x: Int = 5 var y: Int = 6 var hax: MyActor? = nil init() { fakeTask { // Warning! You can remove await // Error! Cannot access actor state in nonisolated closure. _ = await self.hax } } } ``` The reason why this was happening is that we were not understanding that the closure passed to fakeTask is not part of the init and has different isolation from the init (it is nonisolated but does not have access to the init's state). This then caused us to exit early and not properly process the isolation crossing point there. Now, we properly understand that a sending inheritActorContext closure (just like an @sendable closure) has this property in actor initializers. (cherry picked from commit d54e6ba)
(cherry picked from commit d28eef2)
(cherry picked from commit 3685cdd)
1e0aa66
to
1eaf605
Compare
@swift-ci test |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sema bits look reasonable to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good! Just double checked the APIs where we applied this.
Thanks Michael :)
@@ -255,6 +255,8 @@ extension Task where Failure == Error { | |||
@_spi(MainActorUtilities) | |||
@MainActor | |||
@available(SwiftStdlib 5.9, *) | |||
@available(*, deprecated, message: "Use Task.init with a main actor isolated closure instead") | |||
@available(swift, obsoleted: 6.0, message: "Use Task.init with a main actor isolated closure instead") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
Explanation: This PR marks Task.init, Task.detached/et al and all the TaskGroup APIs as taking their operation as a sending non-Sendable parameter instead of as a @sendable parameter. This allows for users to capture non-Sendable values into the closures used to call these APIs. E.x. we can write the following example which we couldn't before:
The rest of the changes in this PR were needed to work around other issues in the compiler that prevented us from doing the above.
Radars:
Original PRs:
sending
closure from a global-actor-isolated function #74382Risk: Low.
Testing: Added tests to the compiler.
Reviewer: N/A