@@ -69,6 +69,7 @@ public struct ImportTS {
6969 let builder = try CallJSEmission (
7070 moduleName: moduleName,
7171 abiName: getter. abiName ( context: nil ) ,
72+ effects: Effects ( isAsync: false , isThrows: true ) ,
7273 returnType: getter. type
7374 )
7475 try builder. call ( )
@@ -94,13 +95,14 @@ public struct ImportTS {
9495
9596 let abiName : String
9697 let moduleName : String
98+ let effects : Effects
9799 let returnType : BridgeType
98100 let context : BridgeContext
99101
100102 var body = CodeFragmentPrinter ( )
101103 var abiParameterForwardings : [ String ] = [ ]
102104 var abiParameterSignatures : [ ( name: String , type: WasmCoreType ) ] = [ ]
103- var abiReturnType : WasmCoreType ?
105+ let abiReturnType : WasmCoreType ?
104106 // Track destructured variable names for multiple lowered parameters
105107 var destructuredVarNames : [ String ] = [ ]
106108 // Stack-lowered parameters should be evaluated in reverse order to match LIFO stacks
@@ -111,15 +113,23 @@ public struct ImportTS {
111113 private var borrowedArguments : [ BorrowedArgument ] = [ ]
112114 private let needsReturnVariable : Bool
113115
114- init ( moduleName: String , abiName: String , returnType: BridgeType , context: BridgeContext = . importTS) throws {
116+ init ( moduleName: String , abiName: String , effects : Effects , returnType: BridgeType , context: BridgeContext = . importTS) throws {
115117 self . moduleName = moduleName
116118 self . abiName = abiName
119+ self . effects = effects
117120 self . returnType = returnType
118121 self . context = context
119122 let liftingInfo = try returnType. liftingReturnInfo ( context: context)
120- needsReturnVariable =
121- !( returnType == . void || returnType. usesSideChannelForOptionalReturn ( )
122- || liftingInfo. valueToLift == nil )
123+ if effects. isAsync || returnType == . void || returnType. usesSideChannelForOptionalReturn ( ) {
124+ abiReturnType = nil
125+ } else {
126+ abiReturnType = liftingInfo. valueToLift
127+ }
128+ needsReturnVariable = abiReturnType != nil
129+
130+ if effects. isAsync {
131+ prependClosureCallbackParams ( )
132+ }
123133 }
124134
125135 func lowerParameter( param: Parameter ) throws {
@@ -216,12 +226,12 @@ public struct ImportTS {
216226 ///
217227 /// Used for async imports where the JS side receives closure-backed
218228 /// resolve/reject callbacks as object references.
219- func prependClosureCallbackParams( ) {
229+ private func prependClosureCallbackParams( ) {
220230 abiParameterSignatures. insert ( contentsOf: [ ( " resolveRef " , . i32) , ( " rejectRef " , . i32) ] , at: 0 )
221231 abiParameterForwardings. insert ( contentsOf: [ " resolveRef " , " rejectRef " ] , at: 0 )
222232 }
223233
224- func call( skipExceptionCheck : Bool = false ) throws {
234+ func call( ) throws {
225235 for stmt in stackLoweringStmts {
226236 body. write ( stmt. description)
227237 }
@@ -254,25 +264,30 @@ public struct ImportTS {
254264
255265 // Add exception check for ImportTS context (skipped for async, where
256266 // errors are funneled through the JS-side reject path)
257- if !skipExceptionCheck && context == . importTS {
267+ if !effects . isAsync && context == . importTS {
258268 body. write ( " if let error = _swift_js_take_exception() { throw error } " )
259269 }
260270 }
261271
262272 func liftReturnValue( ) throws {
273+ if effects. isAsync {
274+ liftAsyncReturnValue ( )
275+ } else {
276+ try liftSyncReturnValue ( )
277+ }
278+ }
279+
280+ private func liftSyncReturnValue( ) throws {
263281 let liftingInfo = try returnType. liftingReturnInfo ( context: context)
264282
265283 if returnType == . void {
266- abiReturnType = nil
267284 return
268285 }
269286
270287 if returnType. usesSideChannelForOptionalReturn ( ) {
271288 // Side channel returns: extern function returns Void, value is retrieved via side channel
272- abiReturnType = nil
273289 body. write ( " return \( returnType. swiftType) .bridgeJSLiftReturnFromSideChannel() " )
274290 } else {
275- abiReturnType = liftingInfo. valueToLift
276291 let liftExpr : String
277292 switch returnType {
278293 case . closure( let signature, _) :
@@ -288,25 +303,24 @@ public struct ImportTS {
288303 }
289304 }
290305
291- func liftAsyncReturnValue( originalReturnType : BridgeType ) {
306+ private func liftAsyncReturnValue( ) {
292307 // For async imports, the extern function takes leading `resolveRef: Int32, rejectRef: Int32`
293308 // and returns void. The JS side calls the resolve/reject closures when the Promise settles.
294309 // The resolve closure is typed to match the return type, so the ABI conversion is handled
295310 // by the existing closure codegen infrastructure — no manual JSValue-to-type switch needed.
296- abiReturnType = nil
297311
298312 // Wrap the existing body (parameter lowering + extern call) in _bjs_awaitPromise
299313 let innerBody = body
300314 body = CodeFragmentPrinter ( )
301315
302316 let rejectFactory = " makeRejectClosure: { JSTypedClosure<(sending JSValue) -> Void>($0) } "
303- if originalReturnType == . void {
317+ if returnType == . void {
304318 let resolveFactory = " makeResolveClosure: { JSTypedClosure<() -> Void>($0) } "
305319 body. write (
306320 " try await _bjs_awaitPromise( \( resolveFactory) , \( rejectFactory) ) { resolveRef, rejectRef in "
307321 )
308322 } else {
309- let resolveSwiftType = originalReturnType . closureSwiftType
323+ let resolveSwiftType = returnType . closureSwiftType
310324 let resolveFactory =
311325 " makeResolveClosure: { JSTypedClosure<(sending \( resolveSwiftType) ) -> Void>($0) } "
312326 body. write (
@@ -318,19 +332,11 @@ public struct ImportTS {
318332 }
319333 body. write ( " } " )
320334
321- if originalReturnType != . void {
335+ if returnType != . void {
322336 body. write ( " return resolved " )
323337 }
324338 }
325339
326- func assignThis( returnType: BridgeType ) {
327- guard case . jsObject = returnType else {
328- preconditionFailure ( " assignThis can only be called with a jsObject return type " )
329- }
330- abiReturnType = . i32
331- body. write ( " self.jsObject = JSObject(id: UInt32(bitPattern: ret)) " )
332- }
333-
334340 func renderImportDecl( ) -> DeclSyntax {
335341 let printer = CodeFragmentPrinter ( )
336342 SwiftCodePattern . buildExternFunctionDecl (
@@ -408,26 +414,17 @@ public struct ImportTS {
408414 _ function: ImportedFunctionSkeleton ,
409415 topLevelDecls: inout [ DeclSyntax ]
410416 ) throws -> [ DeclSyntax ] {
411- // For async functions, the extern returns void (the JS side resolves/rejects
412- // via continuation callbacks). For sync functions, use the actual return type.
413- let abiReturnType : BridgeType = function. effects. isAsync ? . void : function. returnType
414417 let builder = try CallJSEmission (
415418 moduleName: moduleName,
416419 abiName: function. abiName ( context: nil ) ,
417- returnType: abiReturnType
420+ effects: function. effects,
421+ returnType: function. returnType
418422 )
419- if function. effects. isAsync {
420- builder. prependClosureCallbackParams ( )
421- }
422423 for param in function. parameters {
423424 try builder. lowerParameter ( param: param)
424425 }
425- try builder. call ( skipExceptionCheck: function. effects. isAsync)
426- if function. effects. isAsync {
427- builder. liftAsyncReturnValue ( originalReturnType: function. returnType)
428- } else {
429- try builder. liftReturnValue ( )
430- }
426+ try builder. call ( )
427+ try builder. liftReturnValue ( )
431428 topLevelDecls. append ( builder. renderImportDecl ( ) )
432429 return [
433430 builder. renderThunkDecl (
@@ -445,25 +442,18 @@ public struct ImportTS {
445442 var decls : [ DeclSyntax ] = [ ]
446443
447444 func renderMethod( method: ImportedFunctionSkeleton ) throws -> [ DeclSyntax ] {
448- let abiReturnType : BridgeType = method. effects. isAsync ? . void : method. returnType
449445 let builder = try CallJSEmission (
450446 moduleName: moduleName,
451447 abiName: method. abiName ( context: type) ,
452- returnType: abiReturnType
448+ effects: method. effects,
449+ returnType: method. returnType
453450 )
454- if method. effects. isAsync {
455- builder. prependClosureCallbackParams ( )
456- }
457451 try builder. lowerParameter ( param: selfParameter)
458452 for param in method. parameters {
459453 try builder. lowerParameter ( param: param)
460454 }
461- try builder. call ( skipExceptionCheck: method. effects. isAsync)
462- if method. effects. isAsync {
463- builder. liftAsyncReturnValue ( originalReturnType: method. returnType)
464- } else {
465- try builder. liftReturnValue ( )
466- }
455+ try builder. call ( )
456+ try builder. liftReturnValue ( )
467457 topLevelDecls. append ( builder. renderImportDecl ( ) )
468458 return [
469459 builder. renderThunkDecl (
@@ -477,20 +467,12 @@ public struct ImportTS {
477467
478468 func renderStaticMethod( method: ImportedFunctionSkeleton ) throws -> [ DeclSyntax ] {
479469 let abiName = method. abiName ( context: type, operation: " static " )
480- let abiReturnType : BridgeType = method. effects. isAsync ? . void : method. returnType
481- let builder = try CallJSEmission ( moduleName: moduleName, abiName: abiName, returnType: abiReturnType)
482- if method. effects. isAsync {
483- builder. prependClosureCallbackParams ( )
484- }
470+ let builder = try CallJSEmission ( moduleName: moduleName, abiName: abiName, effects: method. effects, returnType: method. returnType)
485471 for param in method. parameters {
486472 try builder. lowerParameter ( param: param)
487473 }
488- try builder. call ( skipExceptionCheck: method. effects. isAsync)
489- if method. effects. isAsync {
490- builder. liftAsyncReturnValue ( originalReturnType: method. returnType)
491- } else {
492- try builder. liftReturnValue ( )
493- }
474+ try builder. call ( )
475+ try builder. liftReturnValue ( )
494476 topLevelDecls. append ( builder. renderImportDecl ( ) )
495477 return [
496478 builder. renderThunkDecl (
@@ -506,6 +488,7 @@ public struct ImportTS {
506488 let builder = try CallJSEmission (
507489 moduleName: moduleName,
508490 abiName: constructor. abiName ( context: type) ,
491+ effects: Effects ( isAsync: false , isThrows: true ) ,
509492 returnType: . jsObject( nil )
510493 )
511494 for param in constructor. parameters {
@@ -527,6 +510,7 @@ public struct ImportTS {
527510 let builder = try CallJSEmission (
528511 moduleName: moduleName,
529512 abiName: getter. abiName ( context: type) ,
513+ effects: Effects ( isAsync: false , isThrows: true ) ,
530514 returnType: getter. type
531515 )
532516 try builder. lowerParameter ( param: selfParameter)
@@ -546,6 +530,7 @@ public struct ImportTS {
546530 let builder = try CallJSEmission (
547531 moduleName: moduleName,
548532 abiName: setter. abiName ( context: type) ,
533+ effects: Effects ( isAsync: false , isThrows: true ) ,
549534 returnType: . void
550535 )
551536 let newValue = Parameter ( label: nil , name: " newValue " , type: setter. type)
0 commit comments