Skip to content

JNI: preserve synchronous actor property witnesses - #4

Merged
teamhimeh merged 1 commit into
qoncept-forkfrom
codex/fix-jni-actor-property-witnesses
Oct 23, 2026
Merged

teamhimeh merged 1 commit into
qoncept-forkfrom
codex/fix-jni-actor-property-witnesses

Conversation

@teamhimeh

Copy link
Copy Markdown
Collaborator

Problem

JNI extraction currently treats actor property accessors as implicitly async even when the property is explicitly nonisolated. It also misses the synchronous access path provided by an immutable actor property that witnesses a nonisolated protocol getter.

For example:

public protocol Identified {
  var identifier: Int64 { get }
}

public actor Record: Identified {
  public let identifier: Int64
  public nonisolated var label: String { "record" }

  public init(identifier: Int64) {
    self.identifier = identifier
  }
}

Both getters can be exposed synchronously, so Java callers can write:

long identifier = record.getIdentifier();
String label = record.getLabel();

Previously, both getters returned CompletableFuture values. Simply removing await is insufficient for identifier: outside the actor's defining module, direct access to the stored property remains isolated. The generated thunk must instead read (record as any Identified).identifier.

Changes

  • Honor explicit nonisolated modifiers for property getters and setters.
  • Recognize immutable actor properties witnessing synchronous, nonthrowing instance getters, including requirements inherited through ordinary protocols.
  • Record the witness protocol and emit the getter call through that protocol, preserving synchronous access across module boundaries.
  • Keep unwitnessed properties, mutable actor properties, async/throwing requirements, and actor-bound requirements on the existing asynchronous path. Protocols or requirements with attributes or unresolved isolation constraints are handled conservatively.
  • Add extraction and generated-binding regressions, Java runtime tests, and user documentation.

Validation

  • Confirmed the new extraction and generator regressions fail before the fix.
  • swift test --disable-experimental-prebuilts --disable-sandbox: passed.
  • ./gradlew :Samples:SwiftJavaExtractJNISampleApp:test --no-daemon: passed (275 Java tests, no failures or skips).
  • Compiled a separate two-module Swift 6 example: the protocol-witness read succeeds, while direct synchronous access to the actor's stored property fails with the expected isolation diagnostic.
  • swift-format lint --strict on changed Swift files and git diff --check: passed.

Tested with Apple Swift 6.4 and JetBrains Runtime 25.0.2 on macOS.

Honor nonisolated property accessors and expose immutable actor properties
through their synchronous protocol getter witnesses. Generate the witness
cast so reads remain valid outside the actor's defining module.

Add extraction, binding generation, and Java runtime regressions while
keeping ordinary actor-isolated properties asynchronous.
@teamhimeh
teamhimeh merged commit 5bcbe9d into qoncept-fork Oct 23, 2026
33 of 42 checks passed
@teamhimeh

Copy link
Copy Markdown
Collaborator Author

#14 needs to be merged when this is submitted to the upstream.

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.

1 participant