Repository navigation
JNI: exclude protocol extension members from callback requirements - #2
Merged
teamhimeh merged 1 commit intoOct 23, 2026
Merged
Conversation
Protocol extensions provide Swift implementations rather than additional Java callback requirements. Distinguish those members at extraction time and filter them when generating Java interfaces, existential boxes, and Swift callback wrappers. Only unsupported requirements declared in the protocol body should prevent a Java implementation. Add regression tests and Java runtime coverage for calling Swift extension helpers through Java callbacks and returned protocol boxes.
Collaborator
Author
|
related: swiftlang#934 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Protocol extension members are currently treated as JNI callback requirements. An extra method becomes an abstract Java method, while a computed property, static helper, or initializer in an extension can disable Java callback implementations entirely, even though Swift already provides its implementation.
Example: Swift extension helpers with a Java implementation
Consider this Swift API:
message()is a protocol requirement that a conformer must implement.decoratedMessage()andlengthalready have implementations in Swift.Before this change, the generator incorrectly adds
decoratedMessage()as an abstract Java method. Adding an extension property such aslengthalso makes the protocol fail the callback-support check, so it cannot be implemented as an ordinary Java callback.With this change, the Java callback contract contains only the actual requirement:
A Java caller can therefore supply just that implementation:
The call goes from Java to Swift's
decorate(), then to Swift'sdecoratedMessage(), and finally back to the Java implementation ofmessage(). Swift supplies the formatting logic; Java supplies the message. Extension properties and static helpers likewise keep their Swift implementations without becoming additional Java callback requirements.The new runtime tests exercise this round trip and also verify that a protocol value returned from Swift can still dispatch its requirements through the generated Java box.
Changes
Future work: expose Swift implementations as Java default methods
The intended end state is to expose supported protocol extension instance methods and property accessors as Java interface
defaultmethods that forward to the existing Swift implementations. Swift would remain the source of the implementation, while Java callers could use the same convenience API directly without implementing additional abstract methods.For the example above, the desired Java API would allow:
These direct calls are a future API, not generated by this PR. Today, the extension implementation is exercised through a Swift entry point such as
MySwiftLibrary.decorate(provider).A future default-method bridge must preserve Swift dispatch semantics: extension-only helpers execute their Swift bodies, and calls from those bodies to protocol requirements dispatch to the Java conformer's implementation. A requirement with a default implementation in a Swift extension remains a protocol requirement; exposing that implementation must also preserve overrides. Static helpers and initializers need separate treatment because Java interface instance
defaultmethods cannot represent them.This PR establishes the prerequisite distinction between protocol requirements and extension implementations. Generating the default-method bridges is intentionally left to a follow-up change.
Validation
swift test --disable-experimental-prebuilts --disable-sandbox: passed../gradlew :Samples:SwiftJavaExtractJNISampleApp:test --no-daemon: passed, including the three new Java runtime tests.swift-format lint --stricton changed Swift files andgit diff --check: passed.Tested with Apple Swift 6.4 and JetBrains Runtime 25.0.2 on macOS.