@@ -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