Skip to content

Fix async JNI strict concurrency#730

Open
nerzh wants to merge 2 commits into
swiftlang:mainfrom
nerzh:fix/variables-strict-concurrency
Open

Fix async JNI strict concurrency#730
nerzh wants to merge 2 commits into
swiftlang:mainfrom
nerzh:fix/variables-strict-concurrency

Conversation

@nerzh
Copy link
Copy Markdown
Contributor

@nerzh nerzh commented May 2, 2026

Problem found:

Swift Java generated JNI wrappers for async Swift functions no longer compile with newer Swift strict concurrency checks. The generated Task closures capture JNI values and temporary Swift conversion values that are not Sendable, so Swift reports data-race risk errors during compilation.

How it was fixed:

I added an unchecked Sendable wrapper for values that must cross into the generated async Task body. The generator now tracks, structurally, which temporary values are created during JNI-to-Swift parameter conversion and wraps only those values before creating the task. Inside the task, the original values are restored from the wrapper and used as before.

This avoids fragile string parsing of generated Swift code and keeps the fix limited to async JNI generation. Existing async JNI tests were updated to match the new generated output.

@nerzh nerzh requested a review from ktoso as a code owner May 2, 2026 10:48
@ktoso
Copy link
Copy Markdown
Collaborator

ktoso commented May 4, 2026

Hi thanks for the PR, I’m on holiday so unable to review deeply here this week.

im worried about unsafe wrappers like this, and would like to explore other options

@nerzh
Copy link
Copy Markdown
Contributor Author

nerzh commented May 6, 2026

@ktoso yes, I agree. I used an unsafe wrapper to avoid changing the approach you were using, because previously there was already an unsafe constant there 🫣


/// Temporary values created by this parameter conversion that must be moved
/// into async task bodies through an unchecked Sendable wrapper.
let asyncTaskCaptureNames: [String]
Copy link
Copy Markdown
Contributor

@sidepelican sidepelican May 7, 2026

Choose a reason for hiding this comment

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

NativeParameter represents a single parameter for original swift functions.
It seems unnatural to include the names of multiple values you want to send.

@nerzh
Copy link
Copy Markdown
Contributor Author

nerzh commented May 14, 2026

@sidepelican I updated this PR, and if I understood you correctly, I tried to move the async capture information out of NativeParameter and into the conversion steps

@sidepelican
Copy link
Copy Markdown
Contributor

@nerzh It seems my explanation wasn't clear enough.
I meant to say that the additional property should be let asyncTaskCaptureName: String.

It seems multiple CaptureNames are required in the tuple, but this can be properly avoided by temporarily placing the tuple into a variable.

I'd like you to first define an async function taking a tuple argument in Samples/SwiftJavaExtractJNISampleApp/Sources/MySwiftLibrary/Async.swift, then verify whether swift build --disable-sandbox works correctly.

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.

3 participants