Add BridgedJob so cancelling a Swift task cancels the bridged Kotlin coroutine - #120
Conversation
The --build-system native pin from skiptools#106 was a stopgap for swiftlang/swift-build#1363, which is fixed; swiftbuild now writes per-architecture product folders. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
9baf60d to
1043d9f
Compare
|
The Baseline: unchanged |
1043d9f to
dec9660
Compare
dec9660 to
417e041
Compare
loadPeerLibrary only looked in the native build system's <triple>/debug folder, so Robolectric tests could not find the host library once swift build defaulted to swiftbuild, which writes to out/Products/<configuration>. Fall back to that folder when the native path does not exist. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The nightly toolchain's swiftbuild reads -module-cache-path from the
swiftc flags and took the following -Xfrontend as its value ("Cannot
recursively create directory at non-absolute path: -Xfrontend"). The
driver option is equivalent under the native build system.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…coroutine Generated Swift for a bridged `async throws` API (skipstone) now awaits the Kotlin `callback_` function inside `withTaskCancellationHandler`. The Kotlin side returns the `kotlinx.coroutines.Job` running the call; `BridgedJob` adopts it, cancels it when the Swift task is cancelled (also when the cancellation arrives before the job exists), and maps a throwable delivered after that cancellation to `CancellationError`. The samples gain a Kotlin function parked in `suspendCancellableCoroutine` whose `invokeOnCancellation` records the cancellation, and the bridge-to-Swift tests cancel it from Swift both once it is parked and before it starts. The test skips itself when the generated bridge predates the skipstone change, so this can land ahead of that release. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
417e041 to
af30e01
Compare
Summary
Runtime half of skiptools/skipstone PR link: cancelling a Swift task that awaits a bridged Kotlin
async throwsAPI now cancels the Kotlin coroutine.BridgedJobis what the generated Swift uses around the await:attach(_:)adopts thekotlinx.coroutines.Jobthe Kotlincallback_function now returns, cancelling it immediately if the task was already cancelled (the handler can run before the call is made).cancel()callsJob.cancel(null)through JNI.error(_:options:)maps a throwable delivered after the cancellation toCancellationError; otherwise it defers toJThrowable.toError.Testing
SkipBridgeToSwiftSamplesgainskotlinAsyncParkingFunction, a Kotlin function parked insuspendCancellableCoroutinewhoseinvokeOnCancellationrecords the cancellation (the pure-Swift branch pollsTask.isCancelledso the plain macOS run keeps the same semantics).BridgeToSwiftSamplesTests.testAsyncCancellationcancels it from Swift once it is parked and again before the call starts. The test support waits for the awaiting task with a 5 s deadline instead of awaiting it directly, so an unfixed bridge fails instead of hanging the suite.swift test --filter 'BridgeToSwiftSamplesTests|XCSkipTests'(Robolectric run through the real JNI bridge):skipbuilt from Propagate Swift task cancellation to bridged Kotlin async throws calls skipstone#281: 70/70 pass, and the parked coroutine observed the cancellation.skip1.9.11 generator the same test fails with "The await did not resume within 5 s of the cancellation" (that is the bug). So that this PR can land ahead of the skipstone release, the test probes the generated bridge (callback_kotlinAsyncParkingFunctionreturningkotlinx.coroutines.Job) and throwsXCTSkipwhen the generator predates the fix; it becomes a real check as soon asskipships with #281.BridgedJobis additive and the rest of the library is untouched.Stacked on #119 (whose
loadPeerLibrarychange lets the Robolectric run find swiftbuild's product folder) so CI here is green on today's Swift 6.4 hosts; those commits drop out once #119 merges.🤖 Generated with Claude Code