Skip to content

[5.6] make initializing expressions for member stored properties nonisolated. #40693

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

Conversation

kavon
Copy link
Member

@kavon kavon commented Dec 22, 2021

Explanation: There was a mismatch between the isolation assigned to the initializing expressions of a stored property member and the actual implementation by the compiler. For example, this program was permitted by the type-checker

@MainActor func getStatus() -> Int { /* ... */ }
@PIDActor func genPID() -> ProcessID { /* ... */ }

class Process {
  @MainActor var status: Int = getStatus()
  @PIDActor var pid: ProcessID = genPID()

  init() {} // Problem: what is the isolation of this init?
}

but it has an impossible-to-satisfy set of constraints on the init. It's not possible to have the init be isolated to both global actors, in order for the init to execute the genStatus and genPID calls. In fact, the init has no isolation at all, and is non-async, so it cannot gain actor isolation in its body at all. So the implementation was ignoring the isolation, despite the typechecker providing it.

This patch changes the isolation for those initializer expressions for instance members, saying that the isolation is unspecified in order to match the implementation.

Scope of Issue: Programs could have concurrency bugs because isolation was not correctly gained at runtime, despite the type-checker permitting the program. It's limited specifically to any initializing expressions of a nominal type's property that is isolated to a global actor, most commonly the MainActor. If the type has a designated initializer that is not also isolated to that same global-actor, then the bug is present in their program.

Risk: (Medium) This patch will most commonly introduce a source break for code that calls or accesses something isolated to the MainActor specifically within an initializing expression of a stored property member. Users must move those expressions so they appear in each designated initializer. If those initializers had the correct isolation, then the source break is a very simple refactoring. But if those initializers had the wrong isolation, then their code previously had a runtime bug and a larger refactoring is required.

Pull Request URL: #40652
Reviewed By: Doug Gregor
Automated Testing: regression test is included
Issue: rdar://84225474

It's possible to create an impossible set of constraints for
instance-member stored properties of a type. For example:

@mainactor func getStatus() -> Int { /* ... */ }
@PIDActor func genPID() -> ProcessID { /* ... */ }

class Process {
  @mainactor var status: Int = getStatus()
  @PIDActor var pid: ProcessID = genPID()

  init() {} // Problem: what is the isolation of this init?
}

We cannot satisfy the isolation of the initilizing expressions,
which demand that genStatus and genPID are run with isolation
from a non-async designated initializer, which is not possible.

This patch changes the isolation for those initializer expressions
for instance members, saying that the isolation is unspecified.

fixes rdar://84225474
@kavon
Copy link
Member Author

kavon commented Dec 22, 2021

@swift-ci please test

@kavon kavon requested a review from DougGregor December 22, 2021 22:17
@kavon
Copy link
Member Author

kavon commented Jan 6, 2022

@swift-ci please nominate

@DougGregor DougGregor merged commit 76c9ec7 into swiftlang:release/5.6 Jan 7, 2022
@kavon kavon deleted the 5.6-property-initializer-isolation branch January 12, 2022 02:34
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.

2 participants