Skip to content

[5.10][SE-0411] Promote IsolatedDefaultValues from an experimental feature to an upcoming feature. #70839

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

Merged
merged 10 commits into from
Jan 11, 2024

Conversation

hborla
Copy link
Member

@hborla hborla commented Jan 11, 2024

  • Explanation:

SE-0411: Isolated Default Values closed an important hole in Swift's static data-race safety model which prevents actor-isolated default stored property values from being synchronously evaluated from outside the actor. For example, the following code is currently valid, but it will crash at runtime at the call to MainActor.assertIsolated():

@MainActor func requiresMainActor() -> Int {
  MainActor.assertIsolated()
  return 0
}

@MainActor struct S {
  var x = requiresMainActor()
  var y: Int
}

nonisolated func call() async {
  let s = await S(y: 10)
}

await call()

This happens because requiresMainActor() is used as a default argument to the member-wise initializer of S, but default arguments are always evaluated in the caller. In this case, the caller is on the generic executor, so the default argument evaluation crashes. Under -enable-upcoming-feature IsolatedDefaultValues, this code is still value, but callees that have isolated default arguments will hop to the isolation domain before evaluating the default arguments.

  • Scope: Only impacts code that builds with -strict-concurrency=complete. Code can also opt into this feature using -enable-upcoming-feature IsolatedDefaultValues. More specifically, this change impacts structs and classes whose stored properties are global actor isolated and their initial values must run on that global actor.
  • Risk:

Medium. This is technically a source breaking change for code that uses isolated stored property initial values in a nonisolated initializer:

@MainActor func requiresMainActor() -> Int {
  MainActor.assertIsolated()
  return 0
}

class C {
  @MainActor var x = requiresMainActor()

  init() {}
}

In Swift 5.9, the above code is valid. With this change, it's invalid under -strict-concurrency=complete:

error: return from initializer without initializing all stored properties
  init() {}
          ^
note: 'self.x' not initialized
  @MainActor var x = requiresMainActor()
                 ^

However, I believe such code is rare in practice, and the common code pattern that currently exhibits data races is like the above example, which remains valid (but safe) under this proposal.

… isolation

boundaries.

(cherry picked from commit 49d6399)
…e corresponding

stored property.

(cherry picked from commit e9750bc)
…nitializers

should be nonisolated if all initialized properties are Sendable with nonisolated
default values.

(cherry picked from commit d6fce01)
…to an

upcoming feature.

(cherry picked from commit 0e71623)
… isolated

default arguments.

(cherry picked from commit 5ac839b)
(cherry picked from commit 97ee101)
@hborla hborla requested a review from a team as a code owner January 11, 2024 05:32
@hborla
Copy link
Member Author

hborla commented Jan 11, 2024

@swift-ci please test

@hborla hborla force-pushed the 5.10-enable-se-0411 branch from ae896ef to aaa1c85 Compare January 11, 2024 14:58
@hborla
Copy link
Member Author

hborla commented Jan 11, 2024

@swift-ci please test

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🍒 release cherry pick Flag: Release branch cherry picks
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants