jextract/jni: Support async closures (#834) - #913
Conversation
- Exclude async closures from matching synchronous KnownJavaFunctionalInterfaces - Generate CompletableFuture return type for async Java functional interfaces - Lower async closure invocation in Swift thunk to await future.get() - Add comprehensive unit tests in JNIClosureTests
|
Would you mind making the PR description less confusing? What does "classification" even mean. And please add runtime tests. The tests just use string but we need runtime tests for primitives as well. I'll hold off reviewing until the test suite is more complete, this looks to me AI generated which we don't mind but please do spend more effort into validating the implementation is entirely correct, it takes much effort to review a partial PR like this. |
…r async closures - Add JavaCompletableFuture and JavaSimpleCompletableFuture bindings in SwiftJava with typed @JavaMethod get() matching JVM method descriptors - Generate JavaCompletableFuture return types on synthetic @javainterface closure wrappers - Lower async Swift closure invocation in native JNI thunk to futureTrue.get() and unbox the result via T.fromJavaObject - Add unit tests for async closures with primitive parameter and return types in JNIClosureTests - Add real JVM integration tests covering void, primitive (Long, Double), background-thread, and exceptional completions in SwiftJavaExtractJNISampleApp
| outParameters: translatedResult.outParameters, | ||
| conversion: translatedResult.conversion | ||
| ) | ||
| } |
There was a problem hiding this comment.
Oh no, actually this has an issue -- try writing a test for async -> Int64? , we're missing conversions here.
| return failed; | ||
| }); | ||
|
|
||
| assertThrows(ExecutionException.class, future::get); |
There was a problem hiding this comment.
Hm, optimally we'd want to get the RuntimeException rethrown i guess... that might be hard to do, ok to do in a follow up PR
There was a problem hiding this comment.
I will open the issue for this.
…sures - Translate async closure return types without leaking downcall out-parameter discriminators - Convert OptionalLong, OptionalInt, OptionalDouble, and Optional<T> in Swift async closure thunks - Propagate exceptions from throwing async closures via try and fail-fast non-throwing closures with try! instead of swallowing errors with try? - Add unit tests for () async -> Int64? and (Int64) async throws -> String in JNIClosureTests - Add runtime integration tests in AsyncTest for optional returns and exceptional completion
…ync closures - Add awaitFutureResult case to UpcallConversionStep to unify sync and async closure result lowering - Guard that the returned future is non-nil and unbox primitive, optional, and object results - Unify escapingClosureLowering in native translation by delegating async closure awaiting to UpcallConversionStep - Update unit tests in JNIClosureTests to assert the non-nil future guard and awaiting logic
Resolves #834.
Previously, async closures passed from Java to Swift were not supported in JNI mode. Passing an async closure either failed to translate or incorrectly matched synchronous functional interfaces like
RunnableorFunction.This adds JNI support for
@escaping (...) async -> Tclosures:KnownJavaFunctionalInterfaces.@FunctionalInterfacewrappers whoseapplymethod returnsCompletableFuture<T>(orSimpleCompletableFuturein legacy future mode).JavaCompletableFutureandJavaSimpleCompletableFutureinSwiftJavawith@JavaMethod public func get() throws -> JavaObject?to match JVM method descriptors during reflection.future$?.get()and unbox the result viaT.fromJavaObject.JNIClosureTestsand real JVM runtime execution tests (void, primitive types, background completion, and exception propagation) inSwiftJavaExtractJNISampleApp.