-
Notifications
You must be signed in to change notification settings - Fork 10.4k
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
Concurrent top-level detection #41061
Merged
etcwilde
merged 4 commits into
swiftlang:main
from
etcwilde:ewilde/async-top-level-detection
Feb 1, 2022
Merged
Concurrent top-level detection #41061
etcwilde
merged 4 commits into
swiftlang:main
from
etcwilde:ewilde/async-top-level-detection
Feb 1, 2022
+322
−88
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This patch replaces the use of the experimental-async-top-level flag with checking the decl context of the top-level variable to determine whether the top-level contexts should be async.
I need to determine when top-level code contains an `await` to determine whether to make the source file an async context. This logic is perfectly encapsulated in the `FindInnerAsync` AST walker. Unfortunately, that is pushed down in Sema/ConstraintSystem and isn't available at the AST level. I've pulled it up into the brace statement so that I can use that as part of determining whether the source file is async in `DeclContext::isAsyncContext`. Unfortunately, statements don't have an AST context or evaluator or I would make this a request.
To help maintain source-compatibility, the presence of an `await` in top-level code to kick the top-level code over to being a concurrent context. This, of course, means that in the test cases that exist today, they will go back to behaving identically to how they did before I added all of this because they don't have any awaits in the top-level. I'll be adding new tests to verify the differences in behavior between swift 5, swift 6, with and without async top level enabled in the next commit.
I've added four nearly identical top-level code tests to ensure the correct diagnostic behaviours. | with await | without await | -------+-------------------------+----------------------------+ Swift 5| async-5-top-level.swift | no-async-5-top-level.swift | -------+-------------------------+----------------------------+ Swift 6| async-6-top-level.swift | no-async-6-top-level.swift | -------+-------------------------+----------------------------+ Swift 5 and Swift 6 without without an await are identical to the behaviour of the corresponding language version without concurrency enabled at all. The differences between the two being whether a warning is emitted about global variables not being safe for concurrency in Swift 6, while no warnings are emitted in Swift 5. Concurrency is where things get more interesting. In Swift 5, top-level variables effectively have implicit `@_predatesConcurrency @MainActor` attributes added. This is to help alleviate some of the burden of switching things over and not break as many scripts things. In this mode, top-level global variables can be used directly in synchronous functions, regardless of which actor they are on. Asynchronous functions have to use them appropriately. In Swift 6, top-level global variables used from nonisolated contexts will receive a proper error saying the function must be isolated to the global actor to use the variables directly.
etcwilde
added
the
concurrency
Feature: umbrella label for concurrency language features
label
Jan 28, 2022
@swift-ci please test |
Build failed |
@swift-ci please test macos |
Build failed |
@swift-ci please test macOS |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This PR gets the semantics for detecting when to make top-level code a concurrent context. For compatibility reasons, we want scripts written in top-level code without concurrency today in Swift 5 to work exactly the same way when the async top-level lands. To ensure this, the top-level needs to detect when concurrency features are being used before behaving as an async context. The implementation of this is to detect when an
await
keyword has been used before switching the top-level code context to an asynchronous context. If there are no suspension points directly in the top-level, the context is not asynchronous.The implications of making the top-level code an asynchronous context include overload resolution behavior and semantics around spinning up a runloop in the implicit
async_Main
function. These two changes to behavior could cause unintended script breakage. Thus, if there are noawait
calls made, the top-level will behave exactly as it did before.