@@ -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,29 @@ 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 (
117+ moduleName : String ,
118+ abiName : String ,
119+ effects : Effects ,
120+ returnType : BridgeType ,
121+ context : BridgeContext = . importTS
122+ ) throws {
115123 self . moduleName = moduleName
116124 self . abiName = abiName
125+ self . effects = effects
117126 self . returnType = returnType
118127 self . context = context
119128 let liftingInfo = try returnType . liftingReturnInfo ( context : context )
120- needsReturnVariable =
121- ! ( returnType == . void || returnType . usesSideChannelForOptionalReturn ( )
122- || liftingInfo . valueToLift == nil )
129+ if effects . isAsync || returnType == . void || returnType . usesSideChannelForOptionalReturn ( ) {
130+ abiReturnType = nil
131+ } else {
132+ abiReturnType = liftingInfo . valueToLift
133+ }
134+ needsReturnVariable = abiReturnType != nil
135+
136+ if effects . isAsync {
137+ prependClosureCallbackParams ( )
138+ }
123139 }
124140
125141 func lowerParameter ( param : Parameter ) throws {
@@ -216,12 +232,12 @@ public struct ImportTS {
216232 ///
217233 /// Used for async imports where the JS side receives closure-backed
218234 /// resolve/reject callbacks as object references.
219- func prependClosureCallbackParams ( ) {
235+ private func prependClosureCallbackParams ( ) {
220236 abiParameterSignatures . insert ( contentsOf : [ ( " resolveRef " , . i32 ) , ( " rejectRef " , . i32 ) ] , at : 0 )
221237 abiParameterForwardings . insert ( contentsOf : [ " resolveRef " , " rejectRef " ] , at : 0 )
222238 }
223239
224- func call ( skipExceptionCheck : Bool = false ) throws {
240+ func call ( ) throws {
225241 for stmt in stackLoweringStmts {
226242 body . write ( stmt . description )
227243 }
@@ -254,25 +270,30 @@ public struct ImportTS {
254270
255271 // Add exception check for ImportTS context (skipped for async, where
256272 // errors are funneled through the JS-side reject path)
257- if ! skipExceptionCheck && context == . importTS {
273+ if ! effects . isAsync && context == . importTS {
258274 body . write ( " if let error = _swift_js_take_exception() { throw error } " )
259275 }
260276 }
261277
262278 func liftReturnValue ( ) throws {
279+ if effects . isAsync {
280+ liftAsyncReturnValue ( )
281+ } else {
282+ try liftSyncReturnValue ( )
283+ }
284+ }
285+
286+ private func liftSyncReturnValue ( ) throws {
263287 let liftingInfo = try returnType . liftingReturnInfo ( context : context )
264288
265289 if returnType == . void {
266- abiReturnType = nil
267290 return
268291 }
269292
270293 if returnType . usesSideChannelForOptionalReturn ( ) {
271294 // Side channel returns: extern function returns Void, value is retrieved via side channel
272- abiReturnType = nil
273295 body . write ( " return \( returnType . swiftType ) .bridgeJSLiftReturnFromSideChannel() " )
274296 } else {
275- abiReturnType = liftingInfo . valueToLift
276297 let liftExpr : String
277298 switch returnType {
278299 case . closure ( let signature , _) :
@@ -288,25 +309,24 @@ public struct ImportTS {
288309 }
289310 }
290311
291- func liftAsyncReturnValue ( originalReturnType : BridgeType ) {
312+ private func liftAsyncReturnValue ( ) {
292313 // For async imports, the extern function takes leading `resolveRef: Int32, rejectRef: Int32`
293314 // and returns void. The JS side calls the resolve/reject closures when the Promise settles.
294315 // The resolve closure is typed to match the return type, so the ABI conversion is handled
295316 // by the existing closure codegen infrastructure — no manual JSValue-to-type switch needed.
296- abiReturnType = nil
297317
298318 // Wrap the existing body (parameter lowering + extern call) in _bjs_awaitPromise
299319 let innerBody = body
300320 body = CodeFragmentPrinter ( )
301321
302322 let rejectFactory = " makeRejectClosure: { JSTypedClosure<(sending JSValue) -> Void>($0) } "
303- if originalReturnType == . void {
323+ if returnType == . void {
304324 let resolveFactory = " makeResolveClosure: { JSTypedClosure<() -> Void>($0) } "
305325 body . write (
306326 " try await _bjs_awaitPromise( \( resolveFactory ) , \( rejectFactory ) ) { resolveRef, rejectRef in "
307327 )
308328 } else {
309- let resolveSwiftType = originalReturnType . closureSwiftType
329+ let resolveSwiftType = returnType . closureSwiftType
310330 let resolveFactory =
311331 " makeResolveClosure: { JSTypedClosure<(sending \( resolveSwiftType ) ) -> Void>($0) } "
312332 body . write (
@@ -318,19 +338,11 @@ public struct ImportTS {
318338 }
319339 body . write ( " } " )
320340
321- if originalReturnType != . void {
341+ if returnType != . void {
322342 body . write ( " return resolved " )
323343 }
324344 }
325345
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-
334346 func renderImportDecl ( ) -> DeclSyntax {
335347 let printer = CodeFragmentPrinter ( )
336348 SwiftCodePattern . buildExternFunctionDecl (
@@ -408,26 +420,17 @@ public struct ImportTS {
408420 _ function : ImportedFunctionSkeleton ,
409421 topLevelDecls : inout [ DeclSyntax ]
410422 ) 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
414423 let builder = try CallJSEmission (
415424 moduleName : moduleName ,
416425 abiName : function . abiName ( context : nil ) ,
417- returnType : abiReturnType
426+ effects : function . effects ,
427+ returnType : function . returnType
418428 )
419- if function . effects . isAsync {
420- builder . prependClosureCallbackParams ( )
421- }
422429 for param in function . parameters {
423430 try builder . lowerParameter ( param : param )
424431 }
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- }
432+ try builder . call ( )
433+ try builder . liftReturnValue ( )
431434 topLevelDecls . append ( builder . renderImportDecl ( ) )
432435 return [
433436 builder . renderThunkDecl (
@@ -445,25 +448,18 @@ public struct ImportTS {
445448 var decls : [ DeclSyntax ] = [ ]
446449
447450 func renderMethod ( method : ImportedFunctionSkeleton ) throws -> [ DeclSyntax ] {
448- let abiReturnType : BridgeType = method . effects . isAsync ? . void : method . returnType
449451 let builder = try CallJSEmission (
450452 moduleName : moduleName ,
451453 abiName : method . abiName ( context : type ) ,
452- returnType : abiReturnType
454+ effects : method . effects ,
455+ returnType : method . returnType
453456 )
454- if method . effects . isAsync {
455- builder . prependClosureCallbackParams ( )
456- }
457457 try builder . lowerParameter ( param : selfParameter )
458458 for param in method . parameters {
459459 try builder . lowerParameter ( param : param )
460460 }
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- }
461+ try builder . call ( )
462+ try builder . liftReturnValue ( )
467463 topLevelDecls . append ( builder . renderImportDecl ( ) )
468464 return [
469465 builder . renderThunkDecl (
@@ -477,20 +473,17 @@ public struct ImportTS {
477473
478474 func renderStaticMethod ( method : ImportedFunctionSkeleton ) throws -> [ DeclSyntax ] {
479475 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- }
476+ let builder = try CallJSEmission (
477+ moduleName : moduleName ,
478+ abiName : abiName ,
479+ effects : method . effects ,
480+ returnType : method . returnType
481+ )
485482 for param in method . parameters {
486483 try builder . lowerParameter ( param : param )
487484 }
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- }
485+ try builder . call ( )
486+ try builder . liftReturnValue ( )
494487 topLevelDecls . append ( builder . renderImportDecl ( ) )
495488 return [
496489 builder . renderThunkDecl (
@@ -506,6 +499,7 @@ public struct ImportTS {
506499 let builder = try CallJSEmission (
507500 moduleName : moduleName ,
508501 abiName : constructor . abiName ( context : type ) ,
502+ effects : Effects ( isAsync : false , isThrows : true ) ,
509503 returnType : . jsObject ( nil )
510504 )
511505 for param in constructor . parameters {
@@ -527,6 +521,7 @@ public struct ImportTS {
527521 let builder = try CallJSEmission (
528522 moduleName : moduleName ,
529523 abiName : getter . abiName ( context : type ) ,
524+ effects : Effects ( isAsync : false , isThrows : true ) ,
530525 returnType : getter . type
531526 )
532527 try builder . lowerParameter ( param : selfParameter )
@@ -546,6 +541,7 @@ public struct ImportTS {
546541 let builder = try CallJSEmission (
547542 moduleName : moduleName ,
548543 abiName : setter . abiName ( context : type ) ,
544+ effects : Effects ( isAsync : false , isThrows : true ) ,
549545 returnType : . void
550546 )
551547 let newValue = Parameter ( label : nil , name : " newValue " , type : setter . type )
0 commit comments