Skip to content

Commit b472133

Browse files
BridgeJS: Centralize closure sig collection in BridgeSkeletonWalker
1 parent 6d36763 commit b472133

File tree

3 files changed

+59
-152
lines changed

3 files changed

+59
-152
lines changed

Plugins/BridgeJS/Sources/BridgeJSCore/ClosureCodegen.swift

Lines changed: 3 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -188,82 +188,10 @@ public struct ClosureCodegen {
188188
}
189189

190190
public func renderSupport(for skeleton: BridgeJSSkeleton) throws -> String? {
191-
let collector = ClosureSignatureCollectorVisitor()
192-
var walker = BridgeTypeWalker(visitor: collector)
191+
let collector = ClosureSignatureCollectorVisitor(moduleName: skeleton.moduleName)
192+
var walker = BridgeSkeletonWalker(visitor: collector)
193193
walker.walk(skeleton)
194-
var closureSignatures = walker.visitor.signatures
195-
196-
// When async imports exist, inject closure signatures for the typed resolve
197-
// and reject callbacks used by _bjs_awaitPromise.
198-
// - Reject always uses (sending JSValue) -> Void
199-
// - Resolve uses a typed closure matching the return type (or () -> Void for void)
200-
// All async callback closures use `sending` parameters so values can be
201-
// transferred through the checked continuation without Sendable constraints.
202-
if let imported = skeleton.imported {
203-
for file in imported.children {
204-
for function in file.functions where function.effects.isAsync {
205-
// Reject callback
206-
closureSignatures.insert(
207-
ClosureSignature(
208-
parameters: [.jsValue],
209-
returnType: .void,
210-
moduleName: skeleton.moduleName,
211-
sendingParameters: true
212-
)
213-
)
214-
// Resolve callback (typed per return type)
215-
if function.returnType == .void {
216-
closureSignatures.insert(
217-
ClosureSignature(
218-
parameters: [],
219-
returnType: .void,
220-
moduleName: skeleton.moduleName
221-
)
222-
)
223-
} else {
224-
closureSignatures.insert(
225-
ClosureSignature(
226-
parameters: [function.returnType],
227-
returnType: .void,
228-
moduleName: skeleton.moduleName,
229-
sendingParameters: true
230-
)
231-
)
232-
}
233-
}
234-
for type in file.types {
235-
for method in (type.methods + type.staticMethods) where method.effects.isAsync {
236-
closureSignatures.insert(
237-
ClosureSignature(
238-
parameters: [.jsValue],
239-
returnType: .void,
240-
moduleName: skeleton.moduleName,
241-
sendingParameters: true
242-
)
243-
)
244-
if method.returnType == .void {
245-
closureSignatures.insert(
246-
ClosureSignature(
247-
parameters: [],
248-
returnType: .void,
249-
moduleName: skeleton.moduleName
250-
)
251-
)
252-
} else {
253-
closureSignatures.insert(
254-
ClosureSignature(
255-
parameters: [method.returnType],
256-
returnType: .void,
257-
moduleName: skeleton.moduleName,
258-
sendingParameters: true
259-
)
260-
)
261-
}
262-
}
263-
}
264-
}
265-
}
266-
194+
let closureSignatures = walker.visitor.signatures
267195
guard !closureSignatures.isEmpty else { return nil }
268196

269197
var decls: [DeclSyntax] = []

Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift

Lines changed: 3 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -636,79 +636,10 @@ public struct BridgeJSLink {
636636

637637
for unified in skeletons {
638638
let moduleName = unified.moduleName
639-
let collector = ClosureSignatureCollectorVisitor()
640-
var walker = BridgeTypeWalker(visitor: collector)
639+
let collector = ClosureSignatureCollectorVisitor(moduleName: moduleName)
640+
var walker = BridgeSkeletonWalker(visitor: collector)
641641
walker.walk(unified)
642-
var closureSignatures = walker.visitor.signatures
643-
644-
// Inject closure signatures for async import resolve/reject callbacks.
645-
// All use sendingParameters: true so values can be transferred
646-
// through checked continuations without Sendable constraints.
647-
if let imported = unified.imported {
648-
for file in imported.children {
649-
for function in file.functions where function.effects.isAsync {
650-
// Reject callback
651-
closureSignatures.insert(
652-
ClosureSignature(
653-
parameters: [.jsValue],
654-
returnType: .void,
655-
moduleName: moduleName,
656-
sendingParameters: true
657-
)
658-
)
659-
// Resolve callback (typed per return type)
660-
if function.returnType == .void {
661-
closureSignatures.insert(
662-
ClosureSignature(
663-
parameters: [],
664-
returnType: .void,
665-
moduleName: moduleName
666-
)
667-
)
668-
} else {
669-
closureSignatures.insert(
670-
ClosureSignature(
671-
parameters: [function.returnType],
672-
returnType: .void,
673-
moduleName: moduleName,
674-
sendingParameters: true
675-
)
676-
)
677-
}
678-
}
679-
for type in file.types {
680-
for method in (type.methods + type.staticMethods) where method.effects.isAsync {
681-
closureSignatures.insert(
682-
ClosureSignature(
683-
parameters: [.jsValue],
684-
returnType: .void,
685-
moduleName: moduleName,
686-
sendingParameters: true
687-
)
688-
)
689-
if method.returnType == .void {
690-
closureSignatures.insert(
691-
ClosureSignature(
692-
parameters: [],
693-
returnType: .void,
694-
moduleName: moduleName
695-
)
696-
)
697-
} else {
698-
closureSignatures.insert(
699-
ClosureSignature(
700-
parameters: [method.returnType],
701-
returnType: .void,
702-
moduleName: moduleName,
703-
sendingParameters: true
704-
)
705-
)
706-
}
707-
}
708-
}
709-
}
710-
}
711-
642+
let closureSignatures = walker.visitor.signatures
712643
guard !closureSignatures.isEmpty else { continue }
713644

714645
intrinsicRegistry.register(name: "swiftClosureHelpers") { helperPrinter in

Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -395,13 +395,19 @@ public struct Parameter: Codable, Equatable, Sendable {
395395
}
396396
}
397397

398-
// MARK: - BridgeType Visitor
398+
// MARK: - BridgeSkeleton Visitor
399399

400-
public protocol BridgeTypeVisitor {
400+
public protocol BridgeSkeletonVisitor {
401401
mutating func visitClosure(_ signature: ClosureSignature, useJSTypedClosure: Bool)
402+
mutating func visitImportedFunction(_ function: ImportedFunctionSkeleton)
402403
}
403404

404-
public struct BridgeTypeWalker<Visitor: BridgeTypeVisitor> {
405+
public extension BridgeSkeletonVisitor {
406+
mutating func visitClosure(_ signature: ClosureSignature, useJSTypedClosure: Bool) {}
407+
mutating func visitImportedFunction(_ function: ImportedFunctionSkeleton) {}
408+
}
409+
410+
public struct BridgeSkeletonWalker<Visitor: BridgeSkeletonVisitor> {
405411
public var visitor: Visitor
406412

407413
public init(visitor: Visitor) {
@@ -487,6 +493,7 @@ public struct BridgeTypeWalker<Visitor: BridgeTypeVisitor> {
487493
}
488494
}
489495
public mutating func walk(_ function: ImportedFunctionSkeleton) {
496+
visitor.visitImportedFunction(function)
490497
walk(function.parameters)
491498
walk(function.returnType)
492499
}
@@ -1160,16 +1167,57 @@ public struct ImportedModuleSkeleton: Codable {
11601167

11611168
// MARK: - Closure signature collection visitor
11621169

1163-
public struct ClosureSignatureCollectorVisitor: BridgeTypeVisitor {
1170+
public struct ClosureSignatureCollectorVisitor: BridgeSkeletonVisitor {
11641171
public var signatures: Set<ClosureSignature> = []
1172+
let moduleName: String
11651173

1166-
public init(signatures: Set<ClosureSignature> = []) {
1174+
public init(moduleName: String, signatures: Set<ClosureSignature> = []) {
1175+
self.moduleName = moduleName
11671176
self.signatures = signatures
11681177
}
11691178

11701179
public mutating func visitClosure(_ signature: ClosureSignature, useJSTypedClosure: Bool) {
11711180
signatures.insert(signature)
11721181
}
1182+
public mutating func visitImportedFunction(_ function: ImportedFunctionSkeleton) {
1183+
guard function.effects.isAsync else { return }
1184+
1185+
// When async imports exist, inject closure signatures for the typed resolve
1186+
// and reject callbacks used by _bjs_awaitPromise.
1187+
// - Reject always uses (sending JSValue) -> Void
1188+
// - Resolve uses a typed closure matching the return type (or () -> Void for void)
1189+
// All async callback closures use `sending` parameters so values can be
1190+
// transferred through the checked continuation without Sendable constraints.
1191+
1192+
// Reject callback
1193+
signatures.insert(
1194+
ClosureSignature(
1195+
parameters: [.jsValue],
1196+
returnType: .void,
1197+
moduleName: moduleName,
1198+
sendingParameters: true
1199+
)
1200+
)
1201+
// Resolve callback (typed per return type)
1202+
if function.returnType == .void {
1203+
signatures.insert(
1204+
ClosureSignature(
1205+
parameters: [],
1206+
returnType: .void,
1207+
moduleName: moduleName
1208+
)
1209+
)
1210+
} else {
1211+
signatures.insert(
1212+
ClosureSignature(
1213+
parameters: [function.returnType],
1214+
returnType: .void,
1215+
moduleName: moduleName,
1216+
sendingParameters: true
1217+
)
1218+
)
1219+
}
1220+
}
11731221
}
11741222

11751223
// MARK: - Unified Skeleton

0 commit comments

Comments
 (0)