@@ -15,7 +15,7 @@ public protocol JSClosureProtocol: JSValueCompatible {
15
15
public class JSOneshotClosure : JSObject , JSClosureProtocol {
16
16
private var hostFuncRef : JavaScriptHostFuncRef = 0
17
17
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) {
19
19
// 1. Fill `id` as zero at first to access `self` to get `ObjectIdentifier`.
20
20
super. init ( id: 0 )
21
21
@@ -34,7 +34,7 @@ public class JSOneshotClosure: JSObject, JSClosureProtocol {
34
34
35
35
#if compiler(>=5.5) && !hasFeature(Embedded)
36
36
@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 {
38
38
JSOneshotClosure ( makeAsyncClosure ( body) )
39
39
}
40
40
#endif
@@ -64,10 +64,10 @@ public class JSOneshotClosure: JSObject, JSClosureProtocol {
64
64
public class JSClosure : JSFunction , JSClosureProtocol {
65
65
66
66
class SharedJSClosure {
67
- private var storage : [ JavaScriptHostFuncRef : ( object: JSObject , body: ( [ JSValue ] ) -> JSValue ) ] = [ : ]
67
+ private var storage : [ JavaScriptHostFuncRef : ( object: JSObject , body: ( sending [ JSValue ] ) -> JSValue ) ] = [ : ]
68
68
init ( ) { }
69
69
70
- subscript( _ key: JavaScriptHostFuncRef ) -> ( object: JSObject , body: ( [ JSValue ] ) -> JSValue ) ? {
70
+ subscript( _ key: JavaScriptHostFuncRef ) -> ( object: JSObject , body: ( sending [ JSValue ] ) -> JSValue ) ? {
71
71
get { storage [ key] }
72
72
set { storage [ key] = newValue }
73
73
}
@@ -93,7 +93,7 @@ public class JSClosure: JSFunction, JSClosureProtocol {
93
93
} )
94
94
}
95
95
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) {
97
97
// 1. Fill `id` as zero at first to access `self` to get `ObjectIdentifier`.
98
98
super. init ( id: 0 )
99
99
@@ -109,7 +109,7 @@ public class JSClosure: JSFunction, JSClosureProtocol {
109
109
110
110
#if compiler(>=5.5) && !hasFeature(Embedded)
111
111
@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 {
113
113
JSClosure ( makeAsyncClosure ( body) )
114
114
}
115
115
#endif
@@ -125,18 +125,29 @@ public class JSClosure: JSFunction, JSClosureProtocol {
125
125
126
126
#if compiler(>=5.5) && !hasFeature(Embedded)
127
127
@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 ) {
129
131
{ arguments in
130
132
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)
131
142
Task {
132
143
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) )
135
146
} catch {
136
147
if let jsError = error as? JSError {
137
- resolver ( . failure( jsError. jsValue) )
148
+ context . resolver ( . failure( jsError. jsValue) )
138
149
} else {
139
- resolver ( . failure( JSError ( message: String ( describing: error) ) . jsValue) )
150
+ context . resolver ( . failure( JSError ( message: String ( describing: error) ) . jsValue) )
140
151
}
141
152
}
142
153
}
@@ -183,13 +194,16 @@ private func makeAsyncClosure(_ body: @escaping ([JSValue]) async throws -> JSVa
183
194
@_cdecl ( " _call_host_function_impl " )
184
195
func _call_host_function_impl(
185
196
_ hostFuncRef: JavaScriptHostFuncRef ,
186
- _ argv: UnsafePointer < RawJSValue > , _ argc: Int32 ,
197
+ _ argv: sending UnsafePointer< RawJSValue > , _ argc: Int32 ,
187
198
_ callbackFuncRef: JavaScriptObjectRef
188
199
) -> Bool {
189
200
guard let ( _, hostFunc) = JSClosure . sharedClosures. wrappedValue [ hostFuncRef] else {
190
201
return true
191
202
}
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
+ }
193
207
let result = hostFunc ( arguments)
194
208
let callbackFuncRef = JSFunction ( id: callbackFuncRef)
195
209
_ = callbackFuncRef ( result)
0 commit comments