Skip to content

[AST/SIL] Expand SIL function type isolation to include nonisolated(nonsending)#88404

Open
xedin wants to merge 10 commits intoswiftlang:mainfrom
xedin:rdar-169998321
Open

[AST/SIL] Expand SIL function type isolation to include nonisolated(nonsending)#88404
xedin wants to merge 10 commits intoswiftlang:mainfrom
xedin:rdar-169998321

Conversation

@xedin
Copy link
Copy Markdown
Contributor

@xedin xedin commented Apr 9, 2026

  • Explanation:

    The primary driver for this change is the OptimizeHopToExecutor pass because it has to check whether a call is a suspension point or not and the most convenient way to rule out nonisolated(nonsending) would be to check a callee but since the nonisolated(nonsending) isolation wasn't represented before it had to go through actor isolation which is not always easier to figure out from SIL. This means that some hops were optimized away even though they shouldn't have been.

    The change includes the following:

    • Adding nonisolated(nonsending) to SILFunctionType;
    • Expanding mangling to support that (uses N to represent the new isolation);
    • Serialization of SILFunctionTypeLayout records has been expanded to store "isolation" instead of just "erased" bit;
    • getSILFunctionType is updated to start producing lowering with nonisolated(nonsending) isolation;
    • FullyApplySite::isCallerIsolationInheriting is updated to check callee instead of reaching of the isolation;
  • Resolves: [concurrency]: nonisolated(nonsending) can unexpectedly lose actor isolation #86083, rdar://169998321

  • Risk: Low to Medium. This is a representation change so it carries some risk of interactions with optimizations beyond specialization.

  • Testing: Added new test-cases to the suite, updated existing tests.

@xedin xedin requested a review from rjmccall April 9, 2026 23:07
@xedin xedin requested a review from a team as a code owner April 9, 2026 23:07
@xedin
Copy link
Copy Markdown
Contributor Author

xedin commented Apr 9, 2026

@swift-ci please test

@xedin
Copy link
Copy Markdown
Contributor Author

xedin commented Apr 10, 2026

@swift-ci please test

xedin added 5 commits April 10, 2026 09:35
Currently there is only `erased` but this is soon to gain
one more - `nonisolated(nonsending)`.
…ation

Similarly to `@isolated(any)` it's sometimes necessary to check
whether a call is to a `nonisolated(nonsending)` function value
i.e. for hop elimination pass and without this isolation support
it has to go trying to figure out the isolation from a callee
which is not possible if it doesn't refer to a `SILFunction *`.
Generalizes how isolation is stored for SILFunctionType and
makes it possible to store not just "erased" but any future
isolation we'd need to add as well.
…ation

If a function type requires an implicit isolation parameter
also set `nonisolated(nonsending)` isolation on it. This helps
us track all of the references to `nonisolated(nonsending)`
functions.
@xedin
Copy link
Copy Markdown
Contributor Author

xedin commented Apr 11, 2026

@swift-ci please test

Copy link
Copy Markdown
Contributor

@jamieQ jamieQ left a comment

Choose a reason for hiding this comment

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

A couple general interest questions for you if you have a moment @xedin:

  1. Why is this approach preferable over a narrower fix to just address the issue in the executor hop optimization pass?
  2. I assume the answer is "no", but is this expected to resolve the other apparent issue with that pass described in #88259?

Comment on lines +5630 to +5631
// Make sure that the invariant that `nonisolated(nonsending)` function
// always has an implicit leading parameter is maintained.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Not sure if it should be done in this PR, but do you think the verifier should enforce that the actor isolation and implicit leading parameters correspond in the expected way? Something like <is_nonisolated_nonsending_isolation> <-> <has_implicit_leading_isolated_param>? Or are there expected cases in which that does not hold?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yeah, I need to think about that some more that’s why I put an assert here for now.

Buffer << 'A';
break;
case Node::Kind::ImplNonisolatedNonsendingIsolation:
Buffer << 'N';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Just out of curiosity, how are the letters for this encoding chosen?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

To minimize possibility of clashes but really arbitrarily, I used the first letter of the attribute and checked where else we use it.

@xedin
Copy link
Copy Markdown
Contributor Author

xedin commented Apr 11, 2026

@swift-ci please test Windows platform

@xedin
Copy link
Copy Markdown
Contributor Author

xedin commented Apr 11, 2026

@jamieQ the reason why I did it this way is because there is no reliable way to make it narrow, we should track the isolation.

Copy link
Copy Markdown
Contributor

@rjmccall rjmccall left a comment

Choose a reason for hiding this comment

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

Generally looks good, except I don't think we want the mangling suppression flag.

@xedin
Copy link
Copy Markdown
Contributor Author

xedin commented Apr 13, 2026

@swift-ci please test

Copy link
Copy Markdown
Contributor

@rjmccall rjmccall left a comment

Choose a reason for hiding this comment

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

Approving because the patch seems overall fine, but I think we probably want to fix the printer.

xedin added 5 commits April 13, 2026 14:18
…g)` isolation of SIL function type

`nonisolated(nonsending)` is a modifier and it's really hard to
work with in SIL because most of the things are represented as
attributes there.
…allee

Instead of trying to from isolation which is not always possible
because that method replies on having a `SILFunction *` being called
which is not the same for i.e. function values.
…implicit leading isolation parameter

Doing so changes isolation because the invariant is that if
the function is `@caller_isolated` it should have an implicit
leading parameter.
@xedin
Copy link
Copy Markdown
Contributor Author

xedin commented Apr 13, 2026

@swift-ci please test

@xedin
Copy link
Copy Markdown
Contributor Author

xedin commented Apr 14, 2026

@swift-ci please smoke test macOS platform

@xedin
Copy link
Copy Markdown
Contributor Author

xedin commented Apr 15, 2026

@swift-ci please smoke test macOS platform

1 similar comment
@xedin
Copy link
Copy Markdown
Contributor Author

xedin commented Apr 15, 2026

@swift-ci please smoke test macOS platform

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.

[concurrency]: nonisolated(nonsending) can unexpectedly lose actor isolation

4 participants