Skip to content

Add discussion of global actor isolation inference. [SE-0316] #371

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

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

hborla
Copy link
Member

@hborla hborla commented Jun 7, 2025

This change adds documentation for isolation inference from class inheritance, overridden methods, and protocol conformances.

These rules are buried in old proposal documents, and they deserve documentation in TSPL, especially because they can be difficult to reason about. These rules were originally added in SE-0316.

This does not cover all cases of actor isolation inference; the rules for isolation inference of closures needs to be covered, but I think that belongs in the Sendable section because it's based on whether or not a closure type can be called from outside the current concurrency context.

I started an RFC thread on the forums about this change here: https://forums.swift.org/t/rfc-documentation-for-isolation-inference-from-classes-and-protocols-se-0316/80343.

This change adds documentation for isolation inference from class
inheritance, overridden methods, and protocol conformances.
@hborla hborla requested review from amartini51 and heckj June 7, 2025 16:42
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.

I made some suggestions for reframing the sentences to use active voice to make it clear the compiler is the bit doing the inferring in these scenarios. Structurally, this introduces 3 patterns to look for - the 3rd being a "contextual" - but I wasn't super clear on how that tied into the 2 subheadings beneath.

And I asked a couple questions in the review about the logic and what was possible that didn't seem entirely spelled out to me, but I may be misunderstanding.

Comment on lines 1403 to 1404
If a superclass is isolated to a global actor, the global actor is
inferred on subclasses. For example, the code below has a main-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
If a superclass is isolated to a global actor, the global actor is
inferred on subclasses. For example, the code below has a main-actor
If a superclass is isolated to a global actor, the compiler infers global actor isolation for its subclasses.
For example, the code below has a main-actor

Reframing to active voice - "the compiler" doing the inferring.

Comment on lines 1429 to 1430
Global actor isolation is also inferred from individual overridden
methods. For example, the following code isolates one method of the
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
Global actor isolation is also inferred from individual overridden
methods. For example, the following code isolates one method of the
The compiler also infers global actor isolation on methods a subclass overrides.
For example, the following code isolates one method of the

Reframing to active voice - "the compiler" doing the inferring.

I know we're in the section on global actors, but a question - If the super class method is declared nonisolated - does that also flow down to the overridden method? Can the developer choose another isolation method for the override?

Comment on lines 1503 to 1505
Now, the `Switch` type itself does not have inferred isolation. The
`toggle` method inside `Switch` is isolated to the main actor, because
the protocol requirement that it implements is isolated to the main 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
Now, the `Switch` type itself does not have inferred isolation. The
`toggle` method inside `Switch` is isolated to the main actor, because
the protocol requirement that it implements is isolated to the main actor.
The `Switch` type itself does not have inferred isolation. The
`toggle` method inside `Switch` is isolated to the main actor, because
the protocol requirement that it implements is isolated to the main actor.

Copy link

@jasongregori jasongregori left a comment

Choose a reason for hiding this comment

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

This is so helpful, thank you! I have some questions below.

}
```

In the above example, `Togglable` and all of its requirements

Choose a reason for hiding this comment

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

The first example says “Vehicle and all of its methods and properties are isolated to the main actor”. This one says “all of its requirements”. After reading the next example, I think (?) that all of Switch’s methods and properties are also isolated to the main actor? Is that right? If so I find the first wording very helpful and clearer and I think it would help to use it here as well. If not, perhaps that fact could be made clearer?

Copy link
Member Author

Choose a reason for hiding this comment

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

I used the language "methods and properties" when talking about concrete types and "requirements" when talking about protocols. But you're right that I should state that when @MainActor is inferred on Switch, all of its methods and properties become isolated to the main actor too.

Choose a reason for hiding this comment

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

Thanks, yeah I think that’s really helpful because it’s changing more than just the requirements.


extension Switch: Togglable {
mutating func toggle() {
isOn.toggle()

Choose a reason for hiding this comment

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

In this example the function toggle is isolated to the main actor but isOn is not isolated to the main actor, is it? And if that’s the case, isn’t it not allowed to use it here?

Copy link
Member Author

Choose a reason for hiding this comment

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

In this example, isOn is nonisolated, which is fine to access from a main actor isolated method.

Choose a reason for hiding this comment

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

Ah, is that because you can only access the toggle function if your Switch is currently living in the main actor and thus any access to isOn would necessarily be on the main actor as well? I always forget about that. Very cool.

@hborla
Copy link
Member Author

hborla commented Jun 8, 2025

I also think there's a meta discussion about whether inference rules belong in the Language Guide. I think we are long over due for a section in the Language Reference on concurrency, and we'll need that regardless of whether we want this change in the guide. I am happy to start working on a concurrency and data-race safety chapter for the Language Reference!

If you have thoughts on this, I'd love to hear them: https://forums.swift.org/t/rfc-documentation-for-isolation-inference-from-classes-and-protocols-se-0316/80343/3

mutating func toggle()
}

struct Switch: Togglable {

Choose a reason for hiding this comment

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

this shouldn’t have Togglable here right? Just in the extension?

Suggested change
struct Switch: Togglable {
struct Switch {


extension Switch: Togglable {
mutating func toggle() {
isOn.toggle()

Choose a reason for hiding this comment

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

Ah, is that because you can only access the toggle function if your Switch is currently living in the main actor and thus any access to isOn would necessarily be on the main actor as well? I always forget about that. Very cool.

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.

One sentence felt really odd to read, so I made a suggestion, but otherwise the changes for active voice were super useful to me. Thank you!

Comment on lines +1402 to +1403
If a superclass has global actor isolation, Swift infers that global actor
on subclasses. For example, the code below has a main-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
If a superclass has global actor isolation, Swift infers that global actor
on subclasses. For example, the code below has a main-actor
If a superclass has global actor isolation, Swift infers the global actor isolation applies to subclasses.
For example, the code below has a main-actor

I found the sentence a little awkward to read, and I think this aligns with what you're saying. Please double check.

Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: "...infers that the global actor isolation applies to subclasses..." or "...infers the global actor isolation to apply to subclasses..."

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