Skip to content

[Concurrency] suppress global variable static checking for @TaskLocal property wrapper declarations #70949

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

sophiapoirier
Copy link
Contributor

@sophiapoirier sophiapoirier commented Jan 17, 2024

Explanation: This change resolves a bug in the SE-0412 implementation that makes it impossible to use the @TaskLocal property wrapper with strict concurrency enabled. This is due to the fact that @TaskLocal property wrappers are required to be static, and their storage is always declared var, and so they appear to the type checker as mutable global state, however the implementation of @TaskLocal ensures isolation to a single task, thereby obviating data race concerns. This change suppresses strict concurrency diagnostics for @TaskLocal declarations. Note that this is a temporary solution for 5.10 to unblock developers from experimenting with strict concurrency. The more complete solution will be to move to a TaskLocal macro as described in rdar://121054518 and will be developed on main branch.

Scope: minor change to skip past @TaskLocal declarations during type checking under strict concurrency and the changes are guarded behind an upcoming feature flag

Issue: rdar://120907014

Risk: low risk given that the change is in functionality that is guarded behind -strict-concurrency=complete feature flag and the fact that @TaskLocal property wrapper instances do not have concurrency concerns.

Testing: lit tests included

Reviewer: @ktoso @hborla

@sophiapoirier sophiapoirier requested review from ktoso and hborla January 17, 2024 02:05
@sophiapoirier sophiapoirier requested a review from a team as a code owner January 17, 2024 02:05
@sophiapoirier sophiapoirier requested a review from xedin January 17, 2024 02:05
// TODO: @TaskLocal should be a macro <rdar://120914014>
if (auto *classDecl =
var->getInterfaceType()->getClassOrBoundGenericClass();
classDecl && classDecl->getName().is("TaskLocal")) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should preferably check for the exact decl rather than the name -- I'll whip up a snippet for it

Copy link
Contributor

@ktoso ktoso Jan 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like so:

          if (auto *classDecl =
                  var->getInterfaceType()->getClassOrBoundGenericClass()) {
            auto &ctx = var->getASTContext();
            auto taskLocalDecl = ctx.getTaskLocalDecl();
            if (classDecl == taskLocalDecl) {
              return isolation;
            }
          }

That'll avoid triggering for user-defined types of the same name

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks very much @ktoso I suspected there was a more robust way to check, and I had seen the TaskLocal info in KnownSDKTypes.def but was unsure how it functioned or might help.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Happy to help :)

Usually if we have a type we know about and want to speak about it we put those into Known... and then can on ASTContext get them to compare etc. 👍

@sophiapoirier sophiapoirier force-pushed the TaskLocal-bypass-global-concurrency branch from 0ee4c9d to b9b9283 Compare January 17, 2024 03:28
@ktoso
Copy link
Contributor

ktoso commented Jan 17, 2024

Failures are the removed warning:


26540 /home/build-user/swift/test/Concurrency/task_local.swift:11:33: error: expected warning not produced
26541   static var number: Int = 0 // expected-complete-warning {{static property 'number' is not concurrency-safe because it is non-isolated global shared mutable state; this is an error in Swift 6}}
26542                             ~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
26543 ····························
26544 /home/build-user/swift/test/Concurrency/task_local.swift:12:6: error: expected note not produced
26545   // expected-complete-note@-1 {{isolate 'number' to a global actor, or convert it to a 'let' constant and conform it to 'Sendable'}}
26546 ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
26547 /home/build-user/swift/test/Concurrency/task_local.swift:15:31: error: expected warning not produced
26548   static var someNil: Int? // expected-complete-warning {{static property 'someNil' is not concurrency-safe because it is non-isolated global shared mutable state; this is an error in Swift 6}}
26549                           ~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
26550 ··························
26551 /home/build-user/swift/test/Concurrency/task_local.swift:16:6: error: expected note not produced
26552   // expected-complete-note@-1 {{isolate 'someNil' to a global actor, or convert it to a 'let' constant and conform it to 'Sendable'}}
26553 ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
26554 /home/build-user/swift/test/Concurrency/task_local.swift:21:6: error: expected warning not produced
26555   // expected-complete-warning@-2 {{static property 'noValue' is not concurrency-safe because it is non-isolated global shared mutable state; this is an error in Swift 6}}
26556 ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
26557 /home/build-user/swift/test/Concurrency/task_local.swift:22:6: error: expected note not produced
26558   // expected-complete-note@-3 {{isolate 'noValue' to a global actor, or convert it to a 'let' constant and conform it to 'Sendable'}}
26559 ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
26560

@hborla
Copy link
Member

hborla commented Jan 17, 2024

Please fill out the 5.10 cherry pick PR description template

@sophiapoirier sophiapoirier force-pushed the TaskLocal-bypass-global-concurrency branch from 6fa5be7 to 4eaef71 Compare January 17, 2024 16:07
@sophiapoirier
Copy link
Contributor Author

@swift-ci please test

@xedin xedin removed their request for review January 17, 2024 21:02
@sophiapoirier sophiapoirier changed the title [Concurrency] bypass global variable static checking for @TaskLocal property wrapper declarations [Concurrency] suppress global variable static checking for @TaskLocal property wrapper declarations Jan 17, 2024
@hborla hborla merged commit 2c77bbc into swiftlang:release/5.10 Jan 25, 2024
@sophiapoirier sophiapoirier deleted the TaskLocal-bypass-global-concurrency branch January 25, 2024 23:57
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.

4 participants