Skip to content

Commit d6630c8

Browse files
authored
Fix Embedded, bump 6.3 Swift toolchain in test.yml (#702)
* Bump Swift toolchain snapshots in `test.yml` Bumping to `2026-03-05` for 6.3 and `2026-03-09` for `main`. * Fix concurrency `@_spi` * Downgrade `main` snapshot to old version * Fix 6.3 build error * EmbeddedApp/main.swift: Fix capitalization in print statement * Add `Examples/EmbeddedConcurrency` * EmbeddedConcurrency: don't use `-c release` for SwiftSyntax Remove the '-c release' option from the build command. * Fix warnings with untyped throws, fix npm install error # Conflicts: # Examples/EmbeddedConcurrency/build.sh * Fix formatting * Bump `build-examples` snapshots to 2026-03-14 * Use 2026-03-09 for `main` development snapshots * Add Swift version check before building examples * Exercise `await` on `JSPromise/value` * Address PR feedback * Move `EmbeddedConcurrencyApp` to fixtures * Temporarily disable `main` snapshots * Removing crashing test from the PR
1 parent abf1c88 commit d6630c8

File tree

6 files changed

+76
-12
lines changed

6 files changed

+76
-12
lines changed

.github/workflows/test.yml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ jobs:
2626
target: "wasm32-unknown-wasip1"
2727
- os: ubuntu-24.04
2828
toolchain:
29-
download-url: https://download.swift.org/swift-6.3-branch/ubuntu2404/swift-6.3-DEVELOPMENT-SNAPSHOT-2025-12-05-a/swift-6.3-DEVELOPMENT-SNAPSHOT-2025-12-05-a-ubuntu24.04.tar.gz
29+
download-url: https://download.swift.org/swift-6.3-branch/ubuntu2404/swift-6.3-DEVELOPMENT-SNAPSHOT-2026-03-05-a/swift-6.3-DEVELOPMENT-SNAPSHOT-2026-03-05-a-ubuntu24.04.tar.gz
3030
wasi-backend: Node
3131
target: "wasm32-unknown-wasip1"
3232
- os: ubuntu-22.04
@@ -167,14 +167,16 @@ jobs:
167167
- uses: actions/checkout@v6
168168
- uses: ./.github/actions/install-swift
169169
with:
170-
download-url: https://download.swift.org/development/ubuntu2204/swift-DEVELOPMENT-SNAPSHOT-2026-02-02-a/swift-DEVELOPMENT-SNAPSHOT-2026-02-02-a-ubuntu22.04.tar.gz
170+
download-url: https://download.swift.org/development/ubuntu2204/swift-DEVELOPMENT-SNAPSHOT-2026-03-09-a/swift-DEVELOPMENT-SNAPSHOT-2026-03-09-a-ubuntu22.04.tar.gz
171171
- uses: swiftwasm/setup-swiftwasm@v2
172172
id: setup-wasm32-unknown-wasip1
173173
with: { target: wasm32-unknown-wasip1 }
174174
- uses: swiftwasm/setup-swiftwasm@v2
175175
id: setup-wasm32-unknown-wasip1-threads
176176
with: { target: wasm32-unknown-wasip1-threads }
177-
- run: ./Utilities/build-examples.sh
177+
- run: |
178+
swift --version
179+
./Utilities/build-examples.sh
178180
env:
179181
SWIFT_SDK_ID_wasm32_unknown_wasip1_threads: ${{ steps.setup-wasm32-unknown-wasip1-threads.outputs.swift-sdk-id }}
180182
SWIFT_SDK_ID_wasm32_unknown_wasip1: ${{ steps.setup-wasm32-unknown-wasip1.outputs.swift-sdk-id }}

Examples/Embedded/Sources/EmbeddedApp/main.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import JavaScriptKit
33
let alert = JSObject.global.alert.object!
44
let document = JSObject.global.document
55

6-
print("Hello from WASM, document title: \(document.title.string ?? "")")
6+
print("Hello from Wasm, document title: \(document.title.string ?? "")")
77

88
var count = 0
99

Sources/JavaScriptEventLoop/JSSending.swift

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,32 @@ extension JSSending {
226226
/// - Parameter isolation: The actor isolation context for this call, used in Swift concurrency.
227227
/// - Returns: The received object of type `T`.
228228
/// - Throws: `JSSendingError` if the sending operation fails, or `JSException` if a JavaScript error occurs.
229+
#if compiler(>=6.4)
230+
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
231+
public func receive(
232+
isolation: isolated (any Actor)? = #isolation,
233+
file: StaticString = #file,
234+
line: UInt = #line
235+
) async throws(JSException) -> T {
236+
#if _runtime(_multithreaded)
237+
let idInDestination = try await withCheckedThrowingContinuation { continuation in
238+
let context = _JSSendingContext(continuation: continuation)
239+
let idInSource = self.storage.idInSource
240+
let transferring = self.storage.transferring ? [idInSource] : []
241+
swjs_request_sending_object(
242+
idInSource,
243+
transferring,
244+
Int32(transferring.count),
245+
self.storage.sourceTid,
246+
Unmanaged.passRetained(context).toOpaque()
247+
)
248+
}
249+
return storage.construct(JSObject(id: idInDestination))
250+
#else
251+
return storage.construct(storage.sourceObject)
252+
#endif
253+
}
254+
#else
229255
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
230256
public func receive(
231257
isolation: isolated (any Actor)? = #isolation,
@@ -250,6 +276,7 @@ extension JSSending {
250276
return storage.construct(storage.sourceObject)
251277
#endif
252278
}
279+
#endif
253280

254281
// 6.0 and below can't compile the following without a compiler crash.
255282
#if compiler(>=6.1)
@@ -341,11 +368,19 @@ extension JSSending {
341368

342369
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
343370
private final class _JSSendingContext: Sendable {
371+
#if compiler(>=6.4)
372+
let continuation: CheckedContinuation<JavaScriptObjectRef, JSException>
373+
374+
init(continuation: CheckedContinuation<JavaScriptObjectRef, JSException>) {
375+
self.continuation = continuation
376+
}
377+
#else
344378
let continuation: CheckedContinuation<JavaScriptObjectRef, Error>
345379

346380
init(continuation: CheckedContinuation<JavaScriptObjectRef, Error>) {
347381
self.continuation = continuation
348382
}
383+
#endif
349384
}
350385

351386
/// Error type representing failures during JavaScript object sending operations.

Sources/JavaScriptEventLoop/JavaScriptEventLoop+ExecutorFactory.swift

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55
// See: https://forums.swift.org/t/pitch-2-custom-main-and-global-executors/78437
66

77
#if compiler(>=6.3)
8-
@_spi(ExperimentalCustomExecutors) import _Concurrency
8+
@_spi(ExperimentalCustomExecutors) @_spi(ExperimentalScheduling) import _Concurrency
99
#else
1010
import _Concurrency
11-
#endif
11+
#endif // #if compiler(>=6.3)
1212
import _CJavaScriptKit
1313

1414
#if compiler(>=6.3)
@@ -40,27 +40,49 @@ extension JavaScriptEventLoop: SchedulingExecutor {
4040
tolerance: C.Duration?,
4141
clock: C
4242
) {
43+
#if hasFeature(Embedded)
44+
#if compiler(>=6.4)
45+
// In Embedded Swift, ContinuousClock and SuspendingClock are unavailable.
46+
// Hand-off the scheduling work to the Clock implementation for custom clocks.
47+
clock.enqueue(
48+
job,
49+
on: self,
50+
at: clock.now.advanced(by: delay),
51+
tolerance: tolerance
52+
)
53+
#else
54+
fatalError(
55+
"Delayed enqueue requires Swift 6.4+ in Embedded mode"
56+
)
57+
#endif // #if compiler(>=6.4) (Embedded)
58+
#else // #if hasFeature(Embedded)
4359
let duration: Duration
4460
// Handle clocks we know
4561
if let _ = clock as? ContinuousClock {
4662
duration = delay as! ContinuousClock.Duration
4763
} else if let _ = clock as? SuspendingClock {
4864
duration = delay as! SuspendingClock.Duration
4965
} else {
50-
// Hand-off the scheduling work to Clock implementation for unknown clocks
66+
#if compiler(>=6.4)
67+
// Hand-off the scheduling work to Clock implementation for unknown clocks.
68+
// Clock.enqueue is only available in the development branch (6.4+).
5169
clock.enqueue(
5270
job,
5371
on: self,
5472
at: clock.now.advanced(by: delay),
5573
tolerance: tolerance
5674
)
5775
return
76+
#else
77+
fatalError("Unsupported clock type; only ContinuousClock and SuspendingClock are supported")
78+
#endif // #if compiler(>=6.4) (non-Embedded)
5879
}
5980
let milliseconds = Self.delayInMilliseconds(from: duration)
6081
self.enqueue(
6182
UnownedJob(job),
6283
withDelay: milliseconds
6384
)
85+
#endif // #if hasFeature(Embedded)
6486
}
6587

6688
private static func delayInMilliseconds(from swiftDuration: Duration) -> Double {
@@ -111,4 +133,4 @@ extension JavaScriptEventLoop: ExecutorFactory {
111133
}
112134
}
113135

114-
#endif // compiler(>=6.3)
136+
#endif // #if compiler(>=6.3)

Sources/JavaScriptEventLoop/JavaScriptEventLoop.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,13 +123,16 @@ public final class JavaScriptEventLoop: SerialExecutor, @unchecked Sendable {
123123
private static func installGlobalExecutorIsolated() {
124124
guard !didInstallGlobalExecutor else { return }
125125
didInstallGlobalExecutor = true
126-
#if compiler(>=6.3)
126+
#if compiler(>=6.3) && !hasFeature(Embedded)
127127
if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, visionOS 9999, *) {
128128
// For Swift 6.3 and above, we can use the new `ExecutorFactory` API
129129
_Concurrency._createExecutors(factory: JavaScriptEventLoop.self)
130130
}
131131
#else
132-
// For Swift 6.1 and below, we need to install the global executor by hook API
132+
// For Swift 6.1 and below, or Embedded Swift, we need to install
133+
// the global executor by hook API. The ExecutorFactory mechanism
134+
// does not work in Embedded Swift because ExecutorImpl.swift is
135+
// excluded from the embedded Concurrency library.
133136
installByLegacyHook()
134137
#endif
135138
}

Sources/JavaScriptKit/BasicObjects/JSTypedArray.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ public final class JSTypedArray<Traits>: JSBridgedClass, ExpressibleByArrayLiter
9898
/// used as the return value for the `withUnsafeBytes(_:)` method. The
9999
/// argument is valid only for the duration of the closure's execution.
100100
/// - Returns: The return value, if any, of the `body` closure parameter.
101-
public func withUnsafeBytes<R>(_ body: (UnsafeBufferPointer<Element>) throws -> R) rethrows -> R {
101+
public func withUnsafeBytes<R, E: Error>(_ body: (UnsafeBufferPointer<Element>) throws(E) -> R) throws(E) -> R {
102102
let buffer = UnsafeMutableBufferPointer<Element>.allocate(capacity: length)
103103
defer { buffer.deallocate() }
104104
copyMemory(to: buffer)
@@ -121,7 +121,9 @@ public final class JSTypedArray<Traits>: JSBridgedClass, ExpressibleByArrayLiter
121121
/// argument is valid only for the duration of the closure's execution.
122122
/// - Returns: The return value, if any, of the `body`async closure parameter.
123123
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
124-
public func withUnsafeBytesAsync<R>(_ body: (UnsafeBufferPointer<Element>) async throws -> R) async rethrows -> R {
124+
public func withUnsafeBytesAsync<R, E: Error>(
125+
_ body: (UnsafeBufferPointer<Element>) async throws(E) -> R
126+
) async throws(E) -> R {
125127
let buffer = UnsafeMutableBufferPointer<Element>.allocate(capacity: length)
126128
defer { buffer.deallocate() }
127129
copyMemory(to: buffer)

0 commit comments

Comments
 (0)