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