@@ -15,7 +15,7 @@ public protocol JSClosureProtocol: JSValueCompatible {
1515public class JSOneshotClosure : JSObject , JSClosureProtocol {
1616 private var hostFuncRef : JavaScriptHostFuncRef = 0
1717
18- public init ( _ body: @escaping ( [ JSValue ] ) -> JSValue , file: String = #fileID, line: UInt32 = #line) {
18+ public init ( _ body: @escaping ( sending [ JSValue ] ) -> JSValue , file: String = #fileID, line: UInt32 = #line) {
1919 // 1. Fill `id` as zero at first to access `self` to get `ObjectIdentifier`.
2020 super. init ( id: 0 )
2121
@@ -34,7 +34,7 @@ public class JSOneshotClosure: JSObject, JSClosureProtocol {
3434
3535 #if compiler(>=5.5) && !hasFeature(Embedded)
3636 @available ( macOS 10 . 15 , iOS 13 . 0 , watchOS 6 . 0 , tvOS 13 . 0 , * )
37- public static func async ( _ body: @escaping ( [ JSValue ] ) async throws -> JSValue ) -> JSOneshotClosure {
37+ public static func async ( _ body: sending @escaping ( sending [ JSValue ] ) async throws -> JSValue ) -> JSOneshotClosure {
3838 JSOneshotClosure ( makeAsyncClosure ( body) )
3939 }
4040 #endif
@@ -64,10 +64,10 @@ public class JSOneshotClosure: JSObject, JSClosureProtocol {
6464public class JSClosure : JSFunction , JSClosureProtocol {
6565
6666 class SharedJSClosure {
67- private var storage : [ JavaScriptHostFuncRef : ( object: JSObject , body: ( [ JSValue ] ) -> JSValue ) ] = [ : ]
67+ private var storage : [ JavaScriptHostFuncRef : ( object: JSObject , body: ( sending [ JSValue ] ) -> JSValue ) ] = [ : ]
6868 init ( ) { }
6969
70- subscript( _ key: JavaScriptHostFuncRef ) -> ( object: JSObject , body: ( [ JSValue ] ) -> JSValue ) ? {
70+ subscript( _ key: JavaScriptHostFuncRef ) -> ( object: JSObject , body: ( sending [ JSValue ] ) -> JSValue ) ? {
7171 get { storage [ key] }
7272 set { storage [ key] = newValue }
7373 }
@@ -93,7 +93,7 @@ public class JSClosure: JSFunction, JSClosureProtocol {
9393 } )
9494 }
9595
96- public init ( _ body: @escaping ( [ JSValue ] ) -> JSValue , file: String = #fileID, line: UInt32 = #line) {
96+ public init ( _ body: @escaping ( sending [ JSValue ] ) -> JSValue , file: String = #fileID, line: UInt32 = #line) {
9797 // 1. Fill `id` as zero at first to access `self` to get `ObjectIdentifier`.
9898 super. init ( id: 0 )
9999
@@ -109,7 +109,7 @@ public class JSClosure: JSFunction, JSClosureProtocol {
109109
110110 #if compiler(>=5.5) && !hasFeature(Embedded)
111111 @available ( macOS 10 . 15 , iOS 13 . 0 , watchOS 6 . 0 , tvOS 13 . 0 , * )
112- public static func async ( _ body: @escaping ( [ JSValue ] ) async throws -> JSValue ) -> JSClosure {
112+ public static func async ( _ body: @Sendable @ escaping ( sending [ JSValue] ) async throws -> JSValue ) -> JSClosure {
113113 JSClosure ( makeAsyncClosure ( body) )
114114 }
115115 #endif
@@ -125,18 +125,29 @@ public class JSClosure: JSFunction, JSClosureProtocol {
125125
126126#if compiler(>=5.5) && !hasFeature(Embedded)
127127@available ( macOS 10 . 15 , iOS 13 . 0 , watchOS 6 . 0 , tvOS 13 . 0 , * )
128- private func makeAsyncClosure( _ body: @escaping ( [ JSValue ] ) async throws -> JSValue ) -> ( ( [ JSValue ] ) -> JSValue ) {
128+ private func makeAsyncClosure(
129+ _ body: sending @escaping ( sending [ JSValue ] ) async throws -> JSValue
130+ ) -> ( ( sending [ JSValue ] ) -> JSValue ) {
129131 { arguments in
130132 JSPromise { resolver in
133+ // NOTE: The context is fully transferred to the unstructured task
134+ // isolation but the compiler can't prove it yet, so we need to
135+ // use `@unchecked Sendable` to make it compile with the Swift 6 mode.
136+ struct Context : @unchecked Sendable {
137+ let resolver : ( JSPromise . Result ) -> Void
138+ let arguments : [ JSValue ]
139+ let body : ( sending [ JSValue ] ) async throws -> JSValue
140+ }
141+ let context = Context ( resolver: resolver, arguments: arguments, body: body)
131142 Task {
132143 do {
133- let result = try await body ( arguments)
134- resolver ( . success( result) )
144+ let result = try await context . body ( context . arguments)
145+ context . resolver ( . success( result) )
135146 } catch {
136147 if let jsError = error as? JSError {
137- resolver ( . failure( jsError. jsValue) )
148+ context . resolver ( . failure( jsError. jsValue) )
138149 } else {
139- resolver ( . failure( JSError ( message: String ( describing: error) ) . jsValue) )
150+ context . resolver ( . failure( JSError ( message: String ( describing: error) ) . jsValue) )
140151 }
141152 }
142153 }
@@ -183,13 +194,16 @@ private func makeAsyncClosure(_ body: @escaping ([JSValue]) async throws -> JSVa
183194@_cdecl ( " _call_host_function_impl " )
184195func _call_host_function_impl(
185196 _ hostFuncRef: JavaScriptHostFuncRef ,
186- _ argv: UnsafePointer < RawJSValue > , _ argc: Int32 ,
197+ _ argv: sending UnsafePointer< RawJSValue > , _ argc: Int32 ,
187198 _ callbackFuncRef: JavaScriptObjectRef
188199) -> Bool {
189200 guard let ( _, hostFunc) = JSClosure . sharedClosures. wrappedValue [ hostFuncRef] else {
190201 return true
191202 }
192- let arguments = UnsafeBufferPointer ( start: argv, count: Int ( argc) ) . map { $0. jsValue}
203+ var arguments : [ JSValue ] = [ ]
204+ for i in 0 ..< Int ( argc) {
205+ arguments. append ( argv [ i] . jsValue)
206+ }
193207 let result = hostFunc ( arguments)
194208 let callbackFuncRef = JSFunction ( id: callbackFuncRef)
195209 _ = callbackFuncRef ( result)
0 commit comments