Skip to content

Add a chapter to the Language Reference for data-race safety. #372

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

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

hborla
Copy link
Member

@hborla hborla commented Jun 10, 2025

This change adds a chapter to the TSPL Language Reference on data-race safety. This is meant to be an exhaustive list of semantic rules that define away low-level data races in Swift code. This is not meant to be an introduction to concurrency -- that's the job of the Concurrency chapter of the Language Guide -- and it's not meant to contain all semantic rules about the concurrency model (such as when async functions are guaranteed to not suspend dynamically, etc). This reference will subsume the data-race safety reference in the Swift migration guide, and is largely inspired by the content there, originally written by @mattmassicotte (thank you!)

I think this documentation is appropriate for the TSPL Language Reference based on the statement in the style guide on the purpose of the reference:

Language Reference, commonly referred to as “the reference”, describes every aspect of the Swift language in complete detail, but it makes no attempt to be an instructional text. Its material is ordered according to the shape of the formal grammar, and it hand-waves over examples and applications. Several places explicitly link back to the guide for examples. It doesn't need to be as approachable for beginners, because the guide handles that, but it does need to be accurate and unambiguous, shining its flashlight into infrequently explored areas of the language. To accomplish that, it sometimes must sacrifice approachability or user-friendliness. That's ok — many readers won't even need the reference, but if the reference is unclear, the readers who need an answer have nowhere else to go.

This data-race safety reference is currently not comprehensive, hence the draft state of this PR, and there are a number of missing concepts off the top of my head, including:

  • Isolated parameters
  • sending parameters
  • Isolated closure capture rules
  • Many detailed rules around region-based isolation, such as async let
  • Isolated conformances
  • Sendable inference for methods references and key paths

I also have not done a sweep over all concurrency-related proposals to make sure their data race safety rules are covered by this reference.

@hborla hborla changed the title Add a draft chapter to the Language Reference for data-race safety. Add a chapter to the Language Reference for data-race safety. Jun 10, 2025
concurrent executor.

A non-isolated asynchronous function that runs on the caller's actor is
deonated with the `nonisolated(nonsending)` keyword:
Copy link

Choose a reason for hiding this comment

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

denoted?

Copy link
Member Author

Choose a reason for hiding this comment

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

Hah, yes, thank you. I should use a spell checker :)

Copy link
Member

@heckj heckj left a comment

Choose a reason for hiding this comment

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

spell check updates - no wording changes.

Eliminate data races at compile time.

The Swift 6 language mode eliminates data races at compile time by
identifying and diagnosing risk of concurrent access to shared state.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
identifying and diagnosing risk of concurrent access to shared state.
identifying and diagnosing the risk of concurrent access to shared state.

3. The variable is a property of a struct and the type of the property
conforms to `Sendable`.

Extensions be marked with `nonisolated`, which promptes Swift to infer
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
Extensions be marked with `nonisolated`, which promptes Swift to infer
Extensions can be marked with `nonisolated`, which promptes Swift to infer

concurrent executor.

A non-isolated asynchronous function that runs on the caller's actor is
deonated with the `nonisolated(nonsending)` keyword:
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
deonated with the `nonisolated(nonsending)` keyword:
denoted with the `nonisolated(nonsending)` keyword:

to an actor to a different actor or a concurrent task. Swift ensures
that access to actor-isolated state only happens within the actor. You
can access `nonisolated` properties and methods from outside the actor,
but access to isolated properties and methods must be done asynchornously.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
but access to isolated properties and methods must be done asynchornously.
but access to isolated properties and methods must be done asynchronously.

are either:

1. Non-isolated and have `Sendable` type, or
2. Isolated to a global actor
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
2. Isolated to a global actor
2. Isolated to a global actor.

A global variable is safe from data races if one of the following
conditions applies:

1. It is a `let`-constant and the type conforms to `Sendable`
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
1. It is a `let`-constant and the type conforms to `Sendable`
1. It is a `let`-constant and the type conforms to `Sendable`.

conditions applies:

1. It is a `let`-constant and the type conforms to `Sendable`
2. It is isolated to a global actor
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
2. It is isolated to a global actor
2. It is isolated to a global actor.

}
```

The implementation of an `@concurrent` function will always switch off

Choose a reason for hiding this comment

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

An @Concurrent? Or do we say the "at"?


* If `r` is synchronous, then `r'` is safe from data races if one of the
following conditions applies:
* The isolation of `r'` matches the isolation of `r'`
Copy link

Choose a reason for hiding this comment

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

Suggested change
* The isolation of `r'` matches the isolation of `r'`
* The isolation of `r'` matches the isolation of `r`

* `r'` is `nonisolated`
* If `r` is asynchronous, then the implementation `r'` is safe from data
races if one of the following conditions applies:
* The isolation of `r'` matches the isolation of `r'`
Copy link

Choose a reason for hiding this comment

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

Suggested change
* The isolation of `r'` matches the isolation of `r'`
* The isolation of `r'` matches the isolation of `r`

mutating func toggle()
}

struct Switch: Togglable {
Copy link

Choose a reason for hiding this comment

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

Suggested change
struct Switch: Togglable {
struct Switch {

You specify that a declaration is non-isolated with the `nonisolated`
keyword. Swift guarantees that non-isolated declarations are safe
to call from anywhere by ensuring that they do not access actor-isolated
state in their implementation. Non-isolated functions safely call other
Copy link

Choose a reason for hiding this comment

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

It's also OK for non-isolated function to access actor properties which are let-constants and of Sendable types. I think it might be worth adding this information, because it's common when conforming an actor to protocols.

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.

5 participants