From edca6f9f4fe2a7d3b3cf6ea99c86562bef9488c3 Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Tue, 22 Sep 2026 15:48:17 +0200 Subject: [PATCH] BridgeJS: Support protocol refinement and constrained imports --- .../Sources/BridgeJSCore/ExportSwift.swift | 52 +- .../BridgeJSCore/ExternalModuleIndex.swift | 15 +- .../Sources/BridgeJSCore/ImportTS.swift | 18 +- .../BridgeJSCore/SwiftToSkeleton.swift | 157 +++++- .../Sources/BridgeJSLink/BridgeJSLink.swift | 36 +- .../BridgeJSSkeleton/BridgeJSSkeleton.swift | 70 ++- .../GenericImportDiagnosticsTests.swift | 113 ++++- .../Inputs/MacroSwift/GenericImports.swift | 22 + .../BridgeJSCodegenTests/Alias.swift | 8 +- .../BridgeJSCodegenTests/DocComments.swift | 18 +- .../BridgeJSCodegenTests/GenericImports.json | 289 ++++++++++- .../BridgeJSCodegenTests/GenericImports.swift | 199 ++++++++ .../BridgeJSCodegenTests/Protocol.swift | 128 ++--- .../ProtocolInClosure.swift | 18 +- .../BridgeJSLinkTests/GenericImports.d.ts | 20 + .../BridgeJSLinkTests/GenericImports.js | 101 ++++ .../Exporting-Swift-Protocols.md | 12 +- .../Importing-JS-Function.md | 12 + .../Generated/BridgeJS.swift | 476 +++++++++++++++--- .../Generated/JavaScript/BridgeJS.json | 366 +++++++++++++- .../ImportGenericAPIs.swift | 54 ++ Tests/prelude.mjs | 9 + 22 files changed, 1933 insertions(+), 260 deletions(-) diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift index 55e3b063c..6b5d3ef76 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift @@ -1425,7 +1425,7 @@ struct ProtocolCodegen { for method in proto.methods { let builder = try ImportTS.CallJSEmission( moduleName: moduleName, - abiName: "_extern_\(method.name)", + abiName: method.abiName, effects: method.effects, returnType: method.returnType, context: .exportSwift @@ -1450,7 +1450,7 @@ struct ProtocolCodegen { printer: externDeclPrinter, moduleName: moduleName, abiName: method.abiName, - functionName: "_extern_\(method.name)", + functionName: method.abiName, abiParameters: builder.abiParameterSignatures, returnType: builder.abiReturnType ) @@ -1478,32 +1478,34 @@ struct ProtocolCodegen { externDecls.append(contentsOf: propertyExternDecls) } - let structDeclPrinter = CodeFragmentPrinter() - structDeclPrinter.write("struct \(wrapperName): \(protocolName), _BridgedSwiftProtocolWrapper {") - structDeclPrinter.indent { - structDeclPrinter.write("let jsObject: JSObject") - structDeclPrinter.nextLine() - - for methodDecl in methodDecls { - structDeclPrinter.write(lines: methodDecl.lines) - structDeclPrinter.nextLine() - } - - for decl in propertyDecls { - structDeclPrinter.write(lines: decl.lines) - structDeclPrinter.nextLine() + var decls: [DeclSyntax] = [] + if !methodDecls.isEmpty || !propertyDecls.isEmpty { + let extensionPrinter = CodeFragmentPrinter() + extensionPrinter.write("extension \(protocolName) where Self: _BridgedSwiftProtocolWrapper {") + extensionPrinter.indent { + var first = true + for decl in methodDecls + propertyDecls { + if !first { extensionPrinter.nextLine() } + first = false + extensionPrinter.write(lines: decl.lines) + } } - structDeclPrinter.write( - multilineString: """ - static func bridgeJSLiftParameter(_ value: Int32) -> Self { - return \(wrapperName)(jsObject: JSObject(id: UInt32(bitPattern: value))) - } - """ - ) + extensionPrinter.write("}") + decls.append("\(raw: extensionPrinter.lines.joined(separator: "\n"))") } - structDeclPrinter.write("}") - return ["\(raw: structDeclPrinter.lines.joined(separator: "\n"))"] + externDecls + decls.append( + """ + struct \(raw: wrapperName): \(raw: protocolName), _BridgedSwiftProtocolWrapper { + let jsObject: JSObject + + static func bridgeJSLiftParameter(_ value: Int32) -> Self { + return \(raw: wrapperName)(jsObject: JSObject(id: UInt32(bitPattern: value))) + } + } + """ + ) + return decls + externDecls } private func renderProtocolProperty( diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ExternalModuleIndex.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ExternalModuleIndex.swift index 33a27d087..b07fada44 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ExternalModuleIndex.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ExternalModuleIndex.swift @@ -7,6 +7,7 @@ public struct ExternalModuleIndex { public struct ExternalType: Equatable { public let moduleName: String public let bridgeType: BridgeType + public var isGenericBridgeableProtocol = false } public enum LookupResult: Equatable { @@ -31,8 +32,12 @@ public struct ExternalModuleIndex { guard let exported = skeleton.exported else { continue } var moduleEntries = entriesByModule[moduleName] ?? [:] - func register(dotPath: String, bridgeType: BridgeType) { - let externalType = ExternalType(moduleName: moduleName, bridgeType: bridgeType) + func register(dotPath: String, bridgeType: BridgeType, isGenericBridgeableProtocol: Bool = false) { + let externalType = ExternalType( + moduleName: moduleName, + bridgeType: bridgeType, + isGenericBridgeableProtocol: isGenericBridgeableProtocol + ) if moduleEntries[dotPath] == nil { moduleEntries[dotPath] = externalType entriesByDotPath[dotPath, default: []].append(externalType) @@ -61,7 +66,11 @@ public struct ExternalModuleIndex { register(dotPath: enumDef.swiftCallName, bridgeType: bridgeType) } for proto in exported.protocols { - register(dotPath: proto.name, bridgeType: .swiftProtocol(proto.name)) + register( + dotPath: proto.name, + bridgeType: .swiftProtocol(proto.name), + isGenericBridgeableProtocol: proto.isGenericBridgeable == true + ) } for alias in exported.aliases { register( diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift index 0ec5457fa..378fe2012 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift @@ -381,7 +381,7 @@ public struct ImportTS { parameters: [Parameter], returnType: BridgeType, effects: Effects, - genericParameters: [String] = [] + genericParameters: [GenericParameter] = [] ) -> DeclSyntax { let printer = CodeFragmentPrinter() let signature = SwiftSignatureBuilder.buildFunctionSignature( @@ -393,7 +393,13 @@ public struct ImportTS { let genericClause = genericParameters.isEmpty ? "" - : "<" + genericParameters.map { "\($0): BridgedSwiftGenericBridgeable" }.joined(separator: ", ") + : "<" + + genericParameters.map { genericParameter in + let constraints = + ["BridgedSwiftGenericBridgeable"] + + (genericParameter.swiftConstraints ?? genericParameter.constraints) + return "\(genericParameter.name): \(constraints.joined(separator: " & "))" + }.joined(separator: ", ") + ">" printer.write("func \(name.backtickIfNeeded())\(genericClause)\(signature) {") printer.indent { @@ -465,7 +471,7 @@ public struct ImportTS { parameters: function.parameters, returnType: function.returnType, effects: function.effects, - genericParameters: function.genericParameterNames + genericParameters: function.genericParameters ?? [] ) .with(\.leadingTrivia, Self.renderDocumentation(documentation: function.documentation)) ] @@ -496,7 +502,7 @@ public struct ImportTS { parameters: [selfParameter] + method.parameters, returnType: method.returnType, effects: method.effects, - genericParameters: method.genericParameterNames + genericParameters: method.genericParameters ?? [] ) ] } @@ -522,7 +528,7 @@ public struct ImportTS { parameters: method.parameters, returnType: method.returnType, effects: method.effects, - genericParameters: method.genericParameterNames + genericParameters: method.genericParameters ?? [] ) ] } @@ -548,7 +554,7 @@ public struct ImportTS { parameters: constructor.parameters, returnType: .jsObject(nil), effects: effects, - genericParameters: constructor.genericParameterNames + genericParameters: constructor.genericParameters ?? [] ) ] } diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift index 63ce68fe5..0f9f79c06 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift @@ -7,6 +7,11 @@ import BridgeJSUtilities import BridgeJSSkeleton #endif +enum GenericConstraintParseResult { + case parsed(GenericParameter) + case failed(message: String) +} + /// Outcome of attempting to resolve a type as a reference to a generic parameter. enum GenericParameterResolution { case resolved(BridgeType) @@ -762,6 +767,13 @@ public final class SwiftToSkeleton { } private func resolveExternal(for type: TypeSyntax, errors: inout [DiagnosticError]) -> BridgeType? { + resolveExternalType(for: type, errors: &errors)?.bridgeType + } + + private func resolveExternalType( + for type: TypeSyntax, + errors: inout [DiagnosticError] + ) -> ExternalModuleIndex.ExternalType? { guard !externalModuleIndex.isEmpty, var components = type.qualifiedComponents @@ -787,7 +799,7 @@ public final class SwiftToSkeleton { switch lookupResult { case .unique(let externalType): usedExternalModules.insert(externalType.moduleName) - return externalType.bridgeType + return externalType case .ambiguous(let candidates): let moduleNames = candidates.map(\.moduleName).sorted().joined(separator: ", ") errors.append( @@ -981,11 +993,94 @@ public final class SwiftToSkeleton { return name.unicodeScalars.dropFirst().allSatisfy { isIdentifierPart($0, isStart: false) } } - fileprivate static func isBridgeableGenericConstraint(_ constraint: String?) -> Bool { + fileprivate static func isBridgeableGenericConstraint(_ constraint: String) -> Bool { constraint == "BridgedSwiftGenericBridgeable" || constraint == "JavaScriptKit.BridgedSwiftGenericBridgeable" } + fileprivate func inheritsGenericBridgeability(for type: TypeSyntax, visited: Set = []) -> Bool { + if Self.isBridgeableGenericConstraint(type.trimmedDescription) { return true } + if let proto = typeDeclResolver.resolve(type)?.as(ProtocolDeclSyntax.self) { + guard !visited.contains(proto.id) else { return false } + return (proto.inheritanceClause?.inheritedTypes ?? []).contains { + inheritsGenericBridgeability(for: $0.type, visited: visited.union([proto.id])) + } + } + var errors: [DiagnosticError] = [] + return resolveExternalType(for: type, errors: &errors)?.isGenericBridgeableProtocol == true + } + + fileprivate func resolveJSProtocolConstraint(for type: TypeSyntax) -> String? { + if let typeDecl = typeDeclResolver.resolve(type) { + guard let protocolDecl = typeDecl.as(ProtocolDeclSyntax.self), + protocolDecl.attributes.hasJSAttribute() + else { + return nil + } + return protocolDecl.name.text + } + var scratchErrors: [DiagnosticError] = [] + if let externalType = resolveExternal(for: type, errors: &scratchErrors), + case .swiftProtocol(let name) = externalType + { + return name + } + return nil + } + + fileprivate func parseGenericParameterConstraints( + _ genericParam: GenericParameterSyntax, + attributeName: String + ) -> GenericConstraintParseResult { + let paramName = genericParam.name.text + guard let inheritedType = genericParam.inheritedType else { + return .failed( + message: + "Generic parameter '\(paramName)' must be constrained to 'BridgedSwiftGenericBridgeable' to be used with \(attributeName)." + ) + } + let elements: [TypeSyntax] + if let composition = inheritedType.as(CompositionTypeSyntax.self) { + elements = composition.elements.map { TypeSyntax($0.type) } + } else { + elements = [inheritedType] + } + var hasBridgeableConstraint = false + var constraints: [String] = [] + var swiftConstraints: [String] = [] + for element in elements { + if SwiftToSkeleton.isBridgeableGenericConstraint(element.trimmedDescription) { + hasBridgeableConstraint = true + continue + } + guard let protocolName = resolveJSProtocolConstraint(for: element) else { + return .failed( + message: + "Generic parameter '\(paramName)' has unsupported constraint '\(element.trimmedDescription)'. " + + "Constraints on generic \(attributeName) declarations must be 'BridgedSwiftGenericBridgeable', " + + "optionally composed with '@JS' protocols (e.g. '\(paramName): BridgedSwiftGenericBridgeable & MyProtocol')." + ) + } + hasBridgeableConstraint = hasBridgeableConstraint || inheritsGenericBridgeability(for: element) + if !constraints.contains(protocolName) { + constraints.append(protocolName) + } + let swiftConstraint = element.is(MemberTypeSyntax.self) ? element.trimmedDescription : protocolName + if !swiftConstraints.contains(swiftConstraint) { + swiftConstraints.append(swiftConstraint) + } + } + guard hasBridgeableConstraint else { + let suggested = (["BridgedSwiftGenericBridgeable"] + swiftConstraints).joined(separator: " & ") + return .failed( + message: + "Generic parameter '\(paramName)' is missing the 'BridgedSwiftGenericBridgeable' constraint. " + + "Write '\(paramName): \(suggested)' to combine it with '@JS' protocol constraints on \(attributeName) declarations." + ) + } + return .parsed(GenericParameter(name: paramName, constraints: constraints, swiftConstraints: swiftConstraints)) + } + } private enum ExportSwiftConstants { @@ -2321,6 +2416,23 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { let protocolUniqueKey = makeKey(name: name, namespace: effectiveNamespace) + var inheritedJSProtocols: [String] = [] + for inherited in node.inheritanceClause?.inheritedTypes ?? [] { + guard let baseName = parent.resolveJSProtocolConstraint(for: inherited.type) else { continue } + guard parent.typeDeclResolver.resolve(inherited.type)?.is(ProtocolDeclSyntax.self) == true else { + diagnose( + node: inherited, + message: "Refining @JS protocol '\(baseName)' from another module is not supported yet.", + hint: + "Declare the inherited requirements on '\(name)' directly, or move the base protocol into this module." + ) + return .skipChildren + } + if !inheritedJSProtocols.contains(baseName) { + inheritedJSProtocols.append(baseName) + } + } + exportedProtocolByName[protocolUniqueKey] = ExportedProtocol( name: name, jsName: jsName, @@ -2355,7 +2467,11 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { properties: exportedProtocolByName[protocolUniqueKey]?.properties ?? [], namespace: effectiveNamespace, jsNamespace: namespaceResult.jsNamespace, - documentation: extractDocumentation(from: node) + documentation: extractDocumentation(from: node), + inheritedJSProtocols: inheritedJSProtocols.isEmpty ? nil : inheritedJSProtocols, + isGenericBridgeable: (node.inheritanceClause?.inheritedTypes ?? []).contains { + parent.inheritsGenericBridgeability(for: $0.type) + } ? true : nil ) exportedProtocolByName[protocolUniqueKey] = exportedProtocol @@ -3453,27 +3569,21 @@ private final class ImportSwiftMacrosAPICollector: SyntaxAnyVisitor { /// /// Returns `nil` when a diagnostic was emitted; an empty array when the /// declaration is not generic. - private func parseGenericParameterNames( + private func parseGenericParameters( genericParameterClause: GenericParameterClauseSyntax?, genericWhereClause: GenericWhereClauseSyntax?, node: Syntax - ) -> [String]? { - var genericParameterNames: [String] = [] + ) -> [GenericParameter]? { + var genericParameters: [GenericParameter] = [] if let genericParameterClause { for genericParam in genericParameterClause.parameters { - let paramName = genericParam.name.text - let constraintText = genericParam.inheritedType?.trimmedDescription - guard SwiftToSkeleton.isBridgeableGenericConstraint(constraintText) else { - errors.append( - DiagnosticError( - node: Syntax(genericParam), - message: - "Generic parameter '\(paramName)' must be constrained to 'BridgedSwiftGenericBridgeable' to be used with @JSFunction." - ) - ) + switch parent.parseGenericParameterConstraints(genericParam, attributeName: "@JSFunction") { + case .failed(let message): + errors.append(DiagnosticError(node: Syntax(genericParam), message: message)) return nil + case .parsed(let genericParameter): + genericParameters.append(genericParameter) } - genericParameterNames.append(paramName) } } if genericWhereClause != nil { @@ -3485,7 +3595,7 @@ private final class ImportSwiftMacrosAPICollector: SyntaxAnyVisitor { ) return nil } - return genericParameterNames + return genericParameters } private func parseConstructor( @@ -3502,7 +3612,7 @@ private final class ImportSwiftMacrosAPICollector: SyntaxAnyVisitor { return nil } guard - let genericParameterNames = parseGenericParameterNames( + let genericParameters = parseGenericParameters( genericParameterClause: initializer.genericParameterClause, genericWhereClause: initializer.genericWhereClause, node: Syntax(initializer) @@ -3510,6 +3620,7 @@ private final class ImportSwiftMacrosAPICollector: SyntaxAnyVisitor { else { return nil } + let genericParameterNames = genericParameters.map(\.name) if !genericParameterNames.isEmpty && effects.isAsync { errors.append( DiagnosticError( @@ -3542,7 +3653,7 @@ private final class ImportSwiftMacrosAPICollector: SyntaxAnyVisitor { return ImportedConstructorSkeleton( parameters: parameters, accessLevel: accessLevel, - genericParameters: genericParameterNames.isEmpty ? nil : genericParameterNames + genericParameters: genericParameters.isEmpty ? nil : genericParameters ) } @@ -3561,7 +3672,7 @@ private final class ImportSwiftMacrosAPICollector: SyntaxAnyVisitor { } guard - let genericParameterNames = parseGenericParameterNames( + let genericParameters = parseGenericParameters( genericParameterClause: node.genericParameterClause, genericWhereClause: node.genericWhereClause, node: Syntax(node) @@ -3570,6 +3681,8 @@ private final class ImportSwiftMacrosAPICollector: SyntaxAnyVisitor { return nil } + let genericParameterNames = genericParameters.map(\.name) + let baseName = SwiftToSkeleton.normalizeIdentifier(node.name.text) let extractedJSName = extractJSName(from: jsFunction) let from = extractJSImportFrom(from: jsFunction) @@ -3632,7 +3745,7 @@ private final class ImportSwiftMacrosAPICollector: SyntaxAnyVisitor { effects: effects, documentation: nil, accessLevel: accessLevel, - genericParameters: genericParameterNames.isEmpty ? nil : genericParameterNames + genericParameters: genericParameters.isEmpty ? nil : genericParameters ) } diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift index 5d41869f8..40b1c13c3 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift @@ -1021,7 +1021,10 @@ public struct BridgeJSLink { for skeleton in exportedSkeletons { for proto in skeleton.protocols { printer.write(lines: renderJSDoc(documentation: proto.documentation, parameters: [])) - printer.write("export interface \(proto.resolvedJSName) {") + let extendsClause = + inheritedProtocolTSNames(of: proto, in: exportedSkeletons) + .map { " extends \($0.joined(separator: ", "))" } ?? "" + printer.write("export interface \(proto.resolvedJSName)\(extendsClause) {") printer.indent { for method in proto.methods { printer.write( @@ -1521,7 +1524,7 @@ public struct BridgeJSLink { // Add methods for method in type.methods { let methodName = method.resolvedJSName - let genericClause = renderGenericClause(method.genericParameterNames) + let genericClause = renderGenericClause(method.genericParameters ?? []) let methodSignature = "\(renderTSPropertyName(methodName))\(genericClause)\(renderTSSignature(parameters: method.parameters, returnType: method.returnType, effects: method.effects));" printer.write(methodSignature) @@ -1681,6 +1684,18 @@ public struct BridgeJSLink { } } + private func inheritedProtocolTSNames(of proto: ExportedProtocol, in skeletons: [ExportedSkeleton]) -> [String]? { + guard let inherited = proto.inheritedJSProtocols, !inherited.isEmpty else { return nil } + return inherited.map { baseName in + for skeleton in skeletons { + if let base = skeleton.protocols.first(where: { $0.name == baseName }) { + return base.resolvedJSName + } + } + return baseName + } + } + /// Resolves public TypeScript names without changing the skeleton's Swift type identities. private func resolveTypeScriptType(_ type: BridgeType) -> String { return Self.resolveTypeScriptType(type, exportedSkeletons: skeletons.compactMap(\.exported)) @@ -1771,8 +1786,15 @@ public struct BridgeJSLink { return "(\(parameterSignatures.joined(separator: ", "))): \(returnTypeWithEffect)" } - private func renderGenericClause(_ genericParameterNames: [String]) -> String { - genericParameterNames.isEmpty ? "" : "<\(genericParameterNames.joined(separator: ", "))>" + private func renderGenericClause(_ genericParameters: [GenericParameter]) -> String { + guard !genericParameters.isEmpty else { return "" } + let renderedParameters = genericParameters.map { genericParameter in + let constraints = genericParameter.constraints.map { resolveTypeScriptType(.swiftProtocol($0)) } + return constraints.isEmpty + ? genericParameter.name + : "\(genericParameter.name) extends \(constraints.joined(separator: " & "))" + } + return "<\(renderedParameters.joined(separator: ", "))>" } private func renderTSPropertyName(_ name: String) -> String { @@ -3767,7 +3789,7 @@ extension BridgeJSLink { try thunkBuilder.call(calleeExpr: calleeExpr) let funcLines = thunkBuilder.renderFunction(name: function.abiName(context: nil)) if function.from == nil { - let genericClause = renderGenericClause(genericParameters) + let genericClause = renderGenericClause(function.genericParameters ?? []) importObjectBuilder.appendDts( [ "\(renderTSPropertyName(jsName))\(genericClause)\(renderTSSignature(parameters: function.parameters, returnType: function.returnType, effects: function.effects));" @@ -3861,14 +3883,14 @@ extension BridgeJSLink { dtsPrinter.indent { if let constructor = type.constructor { let returnType = BridgeType.jsObject(type.name) - let genericClause = renderGenericClause(constructor.genericParameterNames) + let genericClause = renderGenericClause(constructor.genericParameters ?? []) dtsPrinter.write( "new\(genericClause)\(renderTSSignature(parameters: constructor.parameters, returnType: returnType, effects: Effects(isAsync: false, isThrows: false)));" ) } for method in type.staticMethods { let methodName = method.resolvedJSName - let genericClause = renderGenericClause(method.genericParameterNames) + let genericClause = renderGenericClause(method.genericParameters ?? []) let signature = "\(renderTSPropertyName(methodName))\(genericClause)\(renderTSSignature(parameters: method.parameters, returnType: method.returnType, effects: method.effects));" dtsPrinter.write(signature) diff --git a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift index ce85176cc..8da9f2e4e 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift @@ -382,6 +382,14 @@ extension ExportedSkeleton { guard let bridgeType = enumDef.genericBridgeType else { continue } entries.append(GenericBridgeableTypeEntry(swiftName: enumDef.swiftCallName, bridgeType: bridgeType)) } + for proto in protocols where proto.isGenericBridgeable == true { + entries.append( + GenericBridgeableTypeEntry( + swiftName: "Any\(proto.name)", + bridgeType: .swiftProtocol(proto.name) + ) + ) + } return entries } } @@ -546,6 +554,44 @@ public struct Parameter: Codable, Equatable, Sendable { } } +public struct GenericParameter: Codable, Equatable, Hashable, Sendable { + public let name: String + public let constraints: [String] + public let swiftConstraints: [String]? + + public init(name: String, constraints: [String] = [], swiftConstraints: [String]? = nil) { + self.name = name + self.constraints = constraints + self.swiftConstraints = swiftConstraints == constraints ? nil : swiftConstraints + } + + private enum CodingKeys: String, CodingKey { + case name, constraints, swiftConstraints + } + + public init(from decoder: any Decoder) throws { + if let single = try? decoder.singleValueContainer(), let name = try? single.decode(String.self) { + self.name = name + self.constraints = [] + self.swiftConstraints = nil + return + } + let container = try decoder.container(keyedBy: CodingKeys.self) + self.name = try container.decode(String.self, forKey: .name) + self.constraints = try container.decodeIfPresent([String].self, forKey: .constraints) ?? [] + self.swiftConstraints = try container.decodeIfPresent([String].self, forKey: .swiftConstraints) + } + + public func encode(to encoder: any Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(name, forKey: .name) + if !constraints.isEmpty { + try container.encode(constraints, forKey: .constraints) + } + try container.encodeIfPresent(swiftConstraints, forKey: .swiftConstraints) + } +} + // MARK: - BridgeSkeleton Visitor public protocol BridgeSkeletonVisitor { @@ -973,6 +1019,8 @@ public struct ExportedProtocol: Codable, Equatable, NamespacedExportedType { public let namespace: [String]? public let jsNamespace: [String]? public var documentation: String? + public var inheritedJSProtocols: [String]? + public var isGenericBridgeable: Bool? public init( name: String, @@ -981,7 +1029,9 @@ public struct ExportedProtocol: Codable, Equatable, NamespacedExportedType { properties: [ExportedProtocolProperty] = [], namespace: [String]? = nil, jsNamespace: [String]? = nil, - documentation: String? = nil + documentation: String? = nil, + inheritedJSProtocols: [String]? = nil, + isGenericBridgeable: Bool? = nil ) { self.name = name self.jsName = jsName @@ -990,6 +1040,8 @@ public struct ExportedProtocol: Codable, Equatable, NamespacedExportedType { self.namespace = namespace self.jsNamespace = jsNamespace self.documentation = documentation + self.inheritedJSProtocols = inheritedJSProtocols + self.isGenericBridgeable = isGenericBridgeable } } @@ -1397,8 +1449,8 @@ public struct ImportedFunctionSkeleton: Codable { /// determine the access level of bridge-generated helpers (e.g. typed /// closure inits) that surface through this function's signature. public let accessLevel: BridgeJSAccessLevel - public let genericParameters: [String]? - public var genericParameterNames: [String] { genericParameters ?? [] } + public let genericParameters: [GenericParameter]? + public var genericParameterNames: [String] { (genericParameters ?? []).map(\.name) } public var isGeneric: Bool { !genericParameterNames.isEmpty } public var resolvedJSName: String { jsName ?? name } @@ -1412,7 +1464,7 @@ public struct ImportedFunctionSkeleton: Codable { effects: Effects = Effects(isAsync: false, isThrows: true), documentation: String? = nil, accessLevel: BridgeJSAccessLevel = .internal, - genericParameters: [String]? = nil + genericParameters: [GenericParameter]? = nil ) { self.name = name self.jsName = jsName @@ -1439,7 +1491,7 @@ public struct ImportedFunctionSkeleton: Codable { self.effects = try container.decode(Effects.self, forKey: .effects) self.documentation = try container.decodeIfPresent(String.self, forKey: .documentation) self.accessLevel = try container.decodeIfPresent(BridgeJSAccessLevel.self, forKey: .accessLevel) ?? .internal - self.genericParameters = try container.decodeIfPresent([String].self, forKey: .genericParameters) + self.genericParameters = try container.decodeIfPresent([GenericParameter].self, forKey: .genericParameters) } public func abiName(context: ImportedTypeSkeleton?) -> String { @@ -1460,14 +1512,14 @@ public struct ImportedConstructorSkeleton: Codable { /// Source access level of the originating Swift `init`. Inherits from the /// enclosing `@JSClass` type when not annotated explicitly. public let accessLevel: BridgeJSAccessLevel - public let genericParameters: [String]? - public var genericParameterNames: [String] { genericParameters ?? [] } + public let genericParameters: [GenericParameter]? + public var genericParameterNames: [String] { (genericParameters ?? []).map(\.name) } public var isGeneric: Bool { !genericParameterNames.isEmpty } public init( parameters: [Parameter], accessLevel: BridgeJSAccessLevel = .internal, - genericParameters: [String]? = nil + genericParameters: [GenericParameter]? = nil ) { self.parameters = parameters self.accessLevel = accessLevel @@ -1482,7 +1534,7 @@ public struct ImportedConstructorSkeleton: Codable { let container = try decoder.container(keyedBy: CodingKeys.self) self.parameters = try container.decode([Parameter].self, forKey: .parameters) self.accessLevel = try container.decodeIfPresent(BridgeJSAccessLevel.self, forKey: .accessLevel) ?? .internal - self.genericParameters = try container.decodeIfPresent([String].self, forKey: .genericParameters) + self.genericParameters = try container.decodeIfPresent([GenericParameter].self, forKey: .genericParameters) } public func abiName(context: ImportedTypeSkeleton) -> String { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/GenericImportDiagnosticsTests.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/GenericImportDiagnosticsTests.swift index 4a421b73b..f2ff5dc81 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/GenericImportDiagnosticsTests.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/GenericImportDiagnosticsTests.swift @@ -1,9 +1,116 @@ +import Foundation import Testing +@testable import BridgeJSCore +@testable import BridgeJSLink @testable import BridgeJSSkeleton @Suite struct GenericImportDiagnosticsTests { + @Test(arguments: [ + ("protocol P {}", "BridgedSwiftGenericBridgeable & P", "unsupported constraint 'P'"), + ("@JS protocol P {}", "P", "missing the 'BridgedSwiftGenericBridgeable' constraint"), + ]) + func invalidProtocolConstraint(declaration: String, constraint: String, diagnostic: String) { + expectDiagnostic( + source: "\(declaration)\n@JSFunction func f(_ value: T) throws(JSException) -> T", + contains: diagnostic + ) + } + + @Test func qualifiedExternalProtocolConstraint() throws { + let dependency = try makeSkeleton( + "@JS public protocol Node: BridgedSwiftGenericBridgeable {}", + moduleName: "GraphKit" + ) + let decoded = try JSONDecoder().decode(BridgeJSSkeleton.self, from: JSONEncoder().encode(dependency)) + let skeleton = try makeSkeleton( + """ + import GraphKit + protocol Node {} + @JSFunction func f(_ value: T) throws(JSException) -> T + """, + dependencies: [(moduleName: "GraphKit", skeleton: decoded)] + ) + let roundTrip = try JSONDecoder().decode(BridgeJSSkeleton.self, from: JSONEncoder().encode(skeleton)) + let imported = try #require(roundTrip.imported) + #expect( + imported.children.flatMap(\.functions).first?.genericParameters == [ + GenericParameter(name: "T", constraints: ["Node"], swiftConstraints: ["GraphKit.Node"]) + ] + ) + let glue = try #require( + try ImportTS(progress: .silent, moduleName: skeleton.moduleName, skeleton: imported).finalize() + ) + #expect(glue.contains("T: BridgedSwiftGenericBridgeable & GraphKit.Node")) + #expect(roundTrip.usedExternalModules == ["GraphKit"]) + } + + @Test func refinedProtocolRequirementsAndAdapter() throws { + let skeleton = try makeSkeleton( + """ + @JS(namespace: "API") protocol Base: BridgedSwiftGenericBridgeable { + func read() -> Int + var value: Int { get set } + } + @JS protocol Middle: Base {} + @JS("PublicNode", namespace: "API") protocol Node: Middle { + var value: Int { get } + } + @JSFunction func f(_ value: T) throws(JSException) -> T + """ + ) + let exported = try #require(skeleton.exported) + let node = try #require(exported.protocols.first { $0.name == "Node" }) + #expect(node.methods.isEmpty) + #expect(node.properties.map(\.name) == ["value"]) + #expect(node.inheritedJSProtocols == ["Middle"]) + #expect(node.jsName == "PublicNode") + #expect( + exported.genericBridgeableTypeEntries.contains { + $0.swiftName == "AnyNode" && $0.bridgeType == .swiftProtocol("Node") + } + ) + let glue = try #require( + try ExportSwift(progress: .silent, moduleName: skeleton.moduleName, skeleton: exported).finalize() + ) + #expect(glue.contains("extension Base where Self: _BridgedSwiftProtocolWrapper {")) + #expect(glue.contains("extension Node where Self: _BridgedSwiftProtocolWrapper {")) + #expect(!glue.contains("extension Middle where Self")) + #expect(glue.contains("struct AnyNode: Node, _BridgedSwiftProtocolWrapper {")) + #expect(glue.contains("name: \"bjs_Base_read\"")) + #expect(!glue.contains("bjs_Node_read")) + let linked = try BridgeJSLink(skeletons: [skeleton]).link() + #expect(linked.outputDts.contains("f")) + #expect(linked.outputDts.contains("export interface PublicNode extends Middle {")) + #expect(linked.outputDts.contains("export interface Middle extends Base {")) + } + + @Test func externalProtocolRefinementIsRejected() throws { + let dependency = try makeSkeleton("@JS public protocol Base {}", moduleName: "GraphKit") + do { + _ = try makeSkeleton( + "import GraphKit\n@JS protocol Child: GraphKit.Base {}", + dependencies: [(moduleName: "GraphKit", skeleton: dependency)] + ) + Issue.record("Expected external refinement diagnostic") + } catch let error as BridgeJSCoreDiagnosticError { + #expect( + error.diagnostics.contains { + $0.diagnostic.message.contains("from another module is not supported") + } + ) + } + } + + @Test func legacyGenericParameterDecoding() throws { + let constructor = try JSONDecoder().decode( + ImportedConstructorSkeleton.self, + from: Data(#"{"parameters":[],"genericParameters":["T"]}"#.utf8) + ) + #expect(constructor.genericParameters == [GenericParameter(name: "T")]) + } + @Test func genericParameterRequiresBridgeableConstraint() { expectDiagnostic( @@ -48,7 +155,7 @@ import Testing let types = imported.children.flatMap { $0.types } let box = try #require(types.first { $0.name == "Box" }) let method = try #require(box.methods.first { $0.name == "member" }) - #expect(method.genericParameters == ["T"]) + #expect(method.genericParameters == [GenericParameter(name: "T")]) } @Test @@ -65,7 +172,7 @@ import Testing let types = imported.children.flatMap { $0.types } let box = try #require(types.first { $0.name == "Box" }) let constructor = try #require(box.constructor) - #expect(constructor.genericParameters == ["T"]) + #expect(constructor.genericParameters == [GenericParameter(name: "T")]) #expect(constructor.parameters.map(\.type) == [.generic("T")]) } @@ -205,6 +312,6 @@ import Testing let imported = try #require(skeleton.imported) let functions = imported.children.flatMap { $0.functions } let function = try #require(functions.first { $0.name == "make" }) - #expect(function.genericParameters == ["T"]) + #expect(function.genericParameters == [GenericParameter(name: "T")]) } } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/GenericImports.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/GenericImports.swift index 5fd3d0226..546207cd3 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/GenericImports.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/GenericImports.swift @@ -72,3 +72,25 @@ struct GenericPoint { @JSFunction func identity(_ value: T) throws(JSException) -> T @JSFunction static func box(_ value: T) throws(JSException) -> T } + +@JS protocol GenericReadable: BridgedSwiftGenericBridgeable { + func read() -> Int +} + +@JS protocol GenericWritable { + var value: Int { get set } +} + +@JS protocol GenericNode: GenericReadable, GenericWritable {} + +@JSFunction func constrainedRoundTrip(_ value: T) throws(JSException) -> T + +@JSFunction func constrainedComposition( + _ value: T +) throws(JSException) -> T + +@JSClass struct ConstrainedConsumer { + @JSFunction init(_ value: T) throws(JSException) + @JSFunction func accept(_ value: T) throws(JSException) -> T + @JSFunction static func identity(_ value: T) throws(JSException) -> T +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Alias.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Alias.swift index af8a8a453..2529f22d3 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Alias.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Alias.swift @@ -1,6 +1,4 @@ -struct AnyHasOptionalUserId: HasOptionalUserId, _BridgedSwiftProtocolWrapper { - let jsObject: JSObject - +extension HasOptionalUserId where Self: _BridgedSwiftProtocolWrapper { var userId: Optional { get { let jsObjectValue = jsObject.bridgeJSLowerParameter() @@ -8,6 +6,10 @@ struct AnyHasOptionalUserId: HasOptionalUserId, _BridgedSwiftProtocolWrapper { return Optional.bridgeJSLiftReturnFromSideChannel() } } +} + +struct AnyHasOptionalUserId: HasOptionalUserId, _BridgedSwiftProtocolWrapper { + let jsObject: JSObject static func bridgeJSLiftParameter(_ value: Int32) -> Self { return AnyHasOptionalUserId(jsObject: JSObject(id: UInt32(bitPattern: value))) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DocComments.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DocComments.swift index b9c65e28f..05c575b73 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DocComments.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DocComments.swift @@ -1,10 +1,8 @@ -struct AnyListener: Listener, _BridgedSwiftProtocolWrapper { - let jsObject: JSObject - +extension Listener where Self: _BridgedSwiftProtocolWrapper { func onEvent(id: Int) -> Void { let idValue = id.bridgeJSLowerParameter() let jsObjectValue = jsObject.bridgeJSLowerParameter() - _extern_onEvent(jsObjectValue, idValue) + bjs_Listener_onEvent(jsObjectValue, idValue) } var name: String { @@ -14,6 +12,10 @@ struct AnyListener: Listener, _BridgedSwiftProtocolWrapper { return String.bridgeJSLiftReturn(ret) } } +} + +struct AnyListener: Listener, _BridgedSwiftProtocolWrapper { + let jsObject: JSObject static func bridgeJSLiftParameter(_ value: Int32) -> Self { return AnyListener(jsObject: JSObject(id: UInt32(bitPattern: value))) @@ -22,14 +24,14 @@ struct AnyListener: Listener, _BridgedSwiftProtocolWrapper { #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_Listener_onEvent") -fileprivate func _extern_onEvent_extern(_ jsObject: Int32, _ id: Int32) -> Void +fileprivate func bjs_Listener_onEvent_extern(_ jsObject: Int32, _ id: Int32) -> Void #else -fileprivate func _extern_onEvent_extern(_ jsObject: Int32, _ id: Int32) -> Void { +fileprivate func bjs_Listener_onEvent_extern(_ jsObject: Int32, _ id: Int32) -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func _extern_onEvent(_ jsObject: Int32, _ id: Int32) -> Void { - return _extern_onEvent_extern(jsObject, id) +@inline(never) fileprivate func bjs_Listener_onEvent(_ jsObject: Int32, _ id: Int32) -> Void { + return bjs_Listener_onEvent_extern(jsObject, id) } #if arch(wasm32) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GenericImports.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GenericImports.json index c7f3e98ae..9f9f7a834 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GenericImports.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GenericImports.json @@ -172,7 +172,69 @@ ], "protocols" : [ + { + "isGenericBridgeable" : true, + "methods" : [ + { + "abiName" : "bjs_GenericReadable_read", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "read", + "parameters" : [ + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "name" : "GenericReadable", + "properties" : [ + + ] + }, + { + "methods" : [ + + ], + "name" : "GenericWritable", + "properties" : [ + { + "isReadonly" : false, + "name" : "value", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ] + }, + { + "inheritedJSProtocols" : [ + "GenericReadable", + "GenericWritable" + ], + "isGenericBridgeable" : true, + "methods" : [ + + ], + "name" : "GenericNode", + "properties" : [ + + ] + } ], "structs" : [ { @@ -224,7 +286,9 @@ "isThrows" : true }, "genericParameters" : [ - "T" + { + "name" : "T" + } ], "name" : "genericRoundTrip", "parameters" : [ @@ -251,7 +315,9 @@ "isThrows" : true }, "genericParameters" : [ - "T" + { + "name" : "T" + } ], "name" : "genericParse", "parameters" : [ @@ -278,8 +344,12 @@ "isThrows" : true }, "genericParameters" : [ - "T", - "U" + { + "name" : "T" + }, + { + "name" : "U" + } ], "name" : "importGenericCombine", "parameters" : [ @@ -314,8 +384,12 @@ "isThrows" : true }, "genericParameters" : [ - "T", - "t" + { + "name" : "T" + }, + { + "name" : "t" + } ], "name" : "importGenericCaseDistinct", "parameters" : [ @@ -350,7 +424,9 @@ "isThrows" : true }, "genericParameters" : [ - "T" + { + "name" : "T" + } ], "name" : "importGenericArray", "parameters" : [ @@ -385,7 +461,9 @@ "isThrows" : true }, "genericParameters" : [ - "T" + { + "name" : "T" + } ], "name" : "importGenericOptional", "parameters" : [ @@ -422,7 +500,9 @@ "isThrows" : true }, "genericParameters" : [ - "T" + { + "name" : "T" + } ], "name" : "importGenericDictionary", "parameters" : [ @@ -457,7 +537,9 @@ "isThrows" : true }, "genericParameters" : [ - "T" + { + "name" : "T" + } ], "name" : "importGenericAfterOptionalArray", "parameters" : [ @@ -495,6 +577,70 @@ "_0" : "T" } } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + { + "constraints" : [ + "GenericNode" + ], + "name" : "T" + } + ], + "name" : "constrainedRoundTrip", + "parameters" : [ + { + "name" : "value", + "type" : { + "generic" : { + "_0" : "T" + } + } + } + ], + "returnType" : { + "generic" : { + "_0" : "T" + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + { + "constraints" : [ + "GenericWritable" + ], + "name" : "T" + } + ], + "name" : "constrainedComposition", + "parameters" : [ + { + "name" : "value", + "type" : { + "generic" : { + "_0" : "T" + } + } + } + ], + "returnType" : { + "generic" : { + "_0" : "T" + } + } } ], "types" : [ @@ -503,8 +649,12 @@ "constructor" : { "accessLevel" : "internal", "genericParameters" : [ - "T", - "U" + { + "name" : "T" + }, + { + "name" : "U" + } ], "parameters" : [ { @@ -552,7 +702,9 @@ "constructor" : { "accessLevel" : "internal", "genericParameters" : [ - "T" + { + "name" : "T" + } ], "parameters" : [ { @@ -577,7 +729,9 @@ "isThrows" : true }, "genericParameters" : [ - "T" + { + "name" : "T" + } ], "name" : "accept", "parameters" : [ @@ -604,7 +758,9 @@ "isThrows" : true }, "genericParameters" : [ - "T" + { + "name" : "T" + } ], "name" : "identity", "parameters" : [ @@ -637,7 +793,9 @@ "isThrows" : true }, "genericParameters" : [ - "T" + { + "name" : "T" + } ], "name" : "box", "parameters" : [ @@ -657,6 +815,105 @@ } } ] + }, + { + "accessLevel" : "internal", + "constructor" : { + "accessLevel" : "internal", + "genericParameters" : [ + { + "constraints" : [ + "GenericNode" + ], + "name" : "T" + } + ], + "parameters" : [ + { + "name" : "value", + "type" : { + "generic" : { + "_0" : "T" + } + } + } + ] + }, + "getters" : [ + + ], + "methods" : [ + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + { + "constraints" : [ + "GenericNode" + ], + "name" : "T" + } + ], + "name" : "accept", + "parameters" : [ + { + "name" : "value", + "type" : { + "generic" : { + "_0" : "T" + } + } + } + ], + "returnType" : { + "generic" : { + "_0" : "T" + } + } + } + ], + "name" : "ConstrainedConsumer", + "setters" : [ + + ], + "staticMethods" : [ + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + { + "constraints" : [ + "GenericNode" + ], + "name" : "T" + } + ], + "name" : "identity", + "parameters" : [ + { + "name" : "value", + "type" : { + "generic" : { + "_0" : "T" + } + } + } + ], + "returnType" : { + "generic" : { + "_0" : "T" + } + } + } + ] } ] } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GenericImports.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GenericImports.swift index cf07236fc..ecb1512cf 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GenericImports.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GenericImports.swift @@ -1,3 +1,86 @@ +extension GenericReadable where Self: _BridgedSwiftProtocolWrapper { + func read() -> Int { + let jsObjectValue = jsObject.bridgeJSLowerParameter() + let ret = bjs_GenericReadable_read(jsObjectValue) + return Int.bridgeJSLiftReturn(ret) + } +} + +struct AnyGenericReadable: GenericReadable, _BridgedSwiftProtocolWrapper { + let jsObject: JSObject + + static func bridgeJSLiftParameter(_ value: Int32) -> Self { + return AnyGenericReadable(jsObject: JSObject(id: UInt32(bitPattern: value))) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_GenericReadable_read") +fileprivate func bjs_GenericReadable_read_extern(_ jsObject: Int32) -> Int32 +#else +fileprivate func bjs_GenericReadable_read_extern(_ jsObject: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_GenericReadable_read(_ jsObject: Int32) -> Int32 { + return bjs_GenericReadable_read_extern(jsObject) +} + +extension GenericWritable where Self: _BridgedSwiftProtocolWrapper { + var value: Int { + get { + let jsObjectValue = jsObject.bridgeJSLowerParameter() + let ret = bjs_GenericWritable_value_get(jsObjectValue) + return Int.bridgeJSLiftReturn(ret) + } + set { + let newValueValue = newValue.bridgeJSLowerParameter() + let jsObjectValue = jsObject.bridgeJSLowerParameter() + bjs_GenericWritable_value_set(jsObjectValue, newValueValue) + } + } +} + +struct AnyGenericWritable: GenericWritable, _BridgedSwiftProtocolWrapper { + let jsObject: JSObject + + static func bridgeJSLiftParameter(_ value: Int32) -> Self { + return AnyGenericWritable(jsObject: JSObject(id: UInt32(bitPattern: value))) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_GenericWritable_value_get") +fileprivate func bjs_GenericWritable_value_get_extern(_ jsObject: Int32) -> Int32 +#else +fileprivate func bjs_GenericWritable_value_get_extern(_ jsObject: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_GenericWritable_value_get(_ jsObject: Int32) -> Int32 { + return bjs_GenericWritable_value_get_extern(jsObject) +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_GenericWritable_value_set") +fileprivate func bjs_GenericWritable_value_set_extern(_ jsObject: Int32, _ newValue: Int32) -> Void +#else +fileprivate func bjs_GenericWritable_value_set_extern(_ jsObject: Int32, _ newValue: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_GenericWritable_value_set(_ jsObject: Int32, _ newValue: Int32) -> Void { + return bjs_GenericWritable_value_set_extern(jsObject, newValue) +} + +struct AnyGenericNode: GenericNode, _BridgedSwiftProtocolWrapper { + let jsObject: JSObject + + static func bridgeJSLiftParameter(_ value: Int32) -> Self { + return AnyGenericNode(jsObject: JSObject(id: UInt32(bitPattern: value))) + } +} + extension GenericColor: _BridgedSwiftCaseEnum { @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 { return bridgeJSRawValue @@ -207,6 +290,14 @@ extension GenericTagged: BridgedSwiftGenericBridgeable { @_spi(BridgeJS) public static let bridgeJSTypeHandle = GenericTagged.bridgeJSMakeTypeHandle() } +extension AnyGenericReadable: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = AnyGenericReadable.bridgeJSMakeTypeHandle() +} + +extension AnyGenericNode: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = AnyGenericNode.bridgeJSMakeTypeHandle() +} + #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_genericRoundTrip") fileprivate func bjs_genericRoundTrip_extern(_ _generic0TypeId: Int32) -> Void @@ -379,6 +470,48 @@ func _$importGenericAfterOptionalArray(_ value return T.bridgeJSStackPop() } +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_constrainedRoundTrip") +fileprivate func bjs_constrainedRoundTrip_extern(_ _generic0TypeId: Int32) -> Void +#else +fileprivate func bjs_constrainedRoundTrip_extern(_ _generic0TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_constrainedRoundTrip(_ _generic0TypeId: Int32) -> Void { + return bjs_constrainedRoundTrip_extern(_generic0TypeId) +} + +func _$constrainedRoundTrip(_ value: T) throws(JSException) -> T { + value.bridgeJSStackPush() + bjs_constrainedRoundTrip(T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return T.bridgeJSStackPop() +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_constrainedComposition") +fileprivate func bjs_constrainedComposition_extern(_ _generic0TypeId: Int32) -> Void +#else +fileprivate func bjs_constrainedComposition_extern(_ _generic0TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_constrainedComposition(_ _generic0TypeId: Int32) -> Void { + return bjs_constrainedComposition_extern(_generic0TypeId) +} + +func _$constrainedComposition(_ value: T) throws(JSException) -> T { + value.bridgeJSStackPush() + bjs_constrainedComposition(T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return T.bridgeJSStackPop() +} + #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_GenericPairFactory_init") fileprivate func bjs_GenericPairFactory_init_extern(_ tagBytes: Int32, _ tagLength: Int32, _ _generic0TypeId: Int32, _ _generic1TypeId: Int32) -> Int32 @@ -490,6 +623,70 @@ func _$GenericConsumer_identity(_ self: JSObje return T.bridgeJSStackPop() } +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_ConstrainedConsumer_init") +fileprivate func bjs_ConstrainedConsumer_init_extern(_ _generic0TypeId: Int32) -> Int32 +#else +fileprivate func bjs_ConstrainedConsumer_init_extern(_ _generic0TypeId: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_ConstrainedConsumer_init(_ _generic0TypeId: Int32) -> Int32 { + return bjs_ConstrainedConsumer_init_extern(_generic0TypeId) +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_ConstrainedConsumer_identity_static") +fileprivate func bjs_ConstrainedConsumer_identity_static_extern(_ _generic0TypeId: Int32) -> Void +#else +fileprivate func bjs_ConstrainedConsumer_identity_static_extern(_ _generic0TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_ConstrainedConsumer_identity_static(_ _generic0TypeId: Int32) -> Void { + return bjs_ConstrainedConsumer_identity_static_extern(_generic0TypeId) +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_ConstrainedConsumer_accept") +fileprivate func bjs_ConstrainedConsumer_accept_extern(_ self: Int32, _ _generic0TypeId: Int32) -> Void +#else +fileprivate func bjs_ConstrainedConsumer_accept_extern(_ self: Int32, _ _generic0TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_ConstrainedConsumer_accept(_ self: Int32, _ _generic0TypeId: Int32) -> Void { + return bjs_ConstrainedConsumer_accept_extern(self, _generic0TypeId) +} + +func _$ConstrainedConsumer_init(_ value: T) throws(JSException) -> JSObject { + value.bridgeJSStackPush() + let ret = bjs_ConstrainedConsumer_init(T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return JSObject.bridgeJSLiftReturn(ret) +} + +func _$ConstrainedConsumer_identity(_ value: T) throws(JSException) -> T { + value.bridgeJSStackPush() + bjs_ConstrainedConsumer_identity_static(T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return T.bridgeJSStackPop() +} + +func _$ConstrainedConsumer_accept(_ self: JSObject, _ value: T) throws(JSException) -> T { + value.bridgeJSStackPush() + let selfValue = self.bridgeJSLowerParameter() + bjs_ConstrainedConsumer_accept(selfValue, T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return T.bridgeJSStackPop() +} + #if arch(wasm32) @_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) @@ -502,6 +699,8 @@ public func _bjs_TestModule_register_type_handles() { GenericColor.bridgeJSTypeID, GenericMode.bridgeJSTypeID, GenericTagged.bridgeJSTypeID, + AnyGenericReadable.bridgeJSTypeID, + AnyGenericNode.bridgeJSTypeID, ] typeIds.withUnsafeBufferPointer { buffer in _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.swift index ef9beefac..ec3d2f65a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.swift @@ -1,22 +1,20 @@ -struct AnyMyViewControllerDelegate: MyViewControllerDelegate, _BridgedSwiftProtocolWrapper { - let jsObject: JSObject - +extension MyViewControllerDelegate where Self: _BridgedSwiftProtocolWrapper { func onSomethingHappened() -> Void { let jsObjectValue = jsObject.bridgeJSLowerParameter() - _extern_onSomethingHappened(jsObjectValue) + bjs_MyViewControllerDelegate_onSomethingHappened(jsObjectValue) } func onValueChanged(_ value: String) -> Void { value.bridgeJSWithLoweredParameter { (valueBytes, valueLength) in let jsObjectValue = jsObject.bridgeJSLowerParameter() - _extern_onValueChanged(jsObjectValue, valueBytes, valueLength) + bjs_MyViewControllerDelegate_onValueChanged(jsObjectValue, valueBytes, valueLength) } } func onCountUpdated(count: Int) -> Bool { let countValue = count.bridgeJSLowerParameter() let jsObjectValue = jsObject.bridgeJSLowerParameter() - let ret = _extern_onCountUpdated(jsObjectValue, countValue) + let ret = bjs_MyViewControllerDelegate_onCountUpdated(jsObjectValue, countValue) return Bool.bridgeJSLiftReturn(ret) } @@ -24,56 +22,56 @@ struct AnyMyViewControllerDelegate: MyViewControllerDelegate, _BridgedSwiftProto prefix.bridgeJSWithLoweredParameter { (prefixBytes, prefixLength) in suffix.bridgeJSWithLoweredParameter { (suffixBytes, suffixLength) in let jsObjectValue = jsObject.bridgeJSLowerParameter() - _extern_onLabelUpdated(jsObjectValue, prefixBytes, prefixLength, suffixBytes, suffixLength) + bjs_MyViewControllerDelegate_onLabelUpdated(jsObjectValue, prefixBytes, prefixLength, suffixBytes, suffixLength) } } } func isCountEven() -> Bool { let jsObjectValue = jsObject.bridgeJSLowerParameter() - let ret = _extern_isCountEven(jsObjectValue) + let ret = bjs_MyViewControllerDelegate_isCountEven(jsObjectValue) return Bool.bridgeJSLiftReturn(ret) } func onHelperUpdated(_ helper: Helper) -> Void { let helperPointer = helper.bridgeJSLowerParameter() let jsObjectValue = jsObject.bridgeJSLowerParameter() - _extern_onHelperUpdated(jsObjectValue, helperPointer) + bjs_MyViewControllerDelegate_onHelperUpdated(jsObjectValue, helperPointer) } func createHelper() -> Helper { let jsObjectValue = jsObject.bridgeJSLowerParameter() - let ret = _extern_createHelper(jsObjectValue) + let ret = bjs_MyViewControllerDelegate_createHelper(jsObjectValue) return Helper.bridgeJSLiftReturn(ret) } func onOptionalHelperUpdated(_ helper: Optional) -> Void { let (helperIsSome, helperPointer) = helper.bridgeJSLowerParameter() let jsObjectValue = jsObject.bridgeJSLowerParameter() - _extern_onOptionalHelperUpdated(jsObjectValue, helperIsSome, helperPointer) + bjs_MyViewControllerDelegate_onOptionalHelperUpdated(jsObjectValue, helperIsSome, helperPointer) } func createOptionalHelper() -> Optional { let jsObjectValue = jsObject.bridgeJSLowerParameter() - let ret = _extern_createOptionalHelper(jsObjectValue) + let ret = bjs_MyViewControllerDelegate_createOptionalHelper(jsObjectValue) return Optional.bridgeJSLiftReturn(ret) } func createEnum() -> ExampleEnum { let jsObjectValue = jsObject.bridgeJSLowerParameter() - let ret = _extern_createEnum(jsObjectValue) + let ret = bjs_MyViewControllerDelegate_createEnum(jsObjectValue) return ExampleEnum.bridgeJSLiftReturn(ret) } func handleResult(_ result: Result) -> Void { let resultCaseId = result.bridgeJSLowerParameter() let jsObjectValue = jsObject.bridgeJSLowerParameter() - _extern_handleResult(jsObjectValue, resultCaseId) + bjs_MyViewControllerDelegate_handleResult(jsObjectValue, resultCaseId) } func getResult() -> Result { let jsObjectValue = jsObject.bridgeJSLowerParameter() - let ret = _extern_getResult(jsObjectValue) + let ret = bjs_MyViewControllerDelegate_getResult(jsObjectValue) return Result.bridgeJSLiftReturn(ret) } @@ -217,6 +215,10 @@ struct AnyMyViewControllerDelegate: MyViewControllerDelegate, _BridgedSwiftProto bjs_MyViewControllerDelegate_priorityOptional_set(jsObjectValue, newValueIsSome, newValueValue) } } +} + +struct AnyMyViewControllerDelegate: MyViewControllerDelegate, _BridgedSwiftProtocolWrapper { + let jsObject: JSObject static func bridgeJSLiftParameter(_ value: Int32) -> Self { return AnyMyViewControllerDelegate(jsObject: JSObject(id: UInt32(bitPattern: value))) @@ -225,146 +227,146 @@ struct AnyMyViewControllerDelegate: MyViewControllerDelegate, _BridgedSwiftProto #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_onSomethingHappened") -fileprivate func _extern_onSomethingHappened_extern(_ jsObject: Int32) -> Void +fileprivate func bjs_MyViewControllerDelegate_onSomethingHappened_extern(_ jsObject: Int32) -> Void #else -fileprivate func _extern_onSomethingHappened_extern(_ jsObject: Int32) -> Void { +fileprivate func bjs_MyViewControllerDelegate_onSomethingHappened_extern(_ jsObject: Int32) -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func _extern_onSomethingHappened(_ jsObject: Int32) -> Void { - return _extern_onSomethingHappened_extern(jsObject) +@inline(never) fileprivate func bjs_MyViewControllerDelegate_onSomethingHappened(_ jsObject: Int32) -> Void { + return bjs_MyViewControllerDelegate_onSomethingHappened_extern(jsObject) } #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_onValueChanged") -fileprivate func _extern_onValueChanged_extern(_ jsObject: Int32, _ valueBytes: Int32, _ valueLength: Int32) -> Void +fileprivate func bjs_MyViewControllerDelegate_onValueChanged_extern(_ jsObject: Int32, _ valueBytes: Int32, _ valueLength: Int32) -> Void #else -fileprivate func _extern_onValueChanged_extern(_ jsObject: Int32, _ valueBytes: Int32, _ valueLength: Int32) -> Void { +fileprivate func bjs_MyViewControllerDelegate_onValueChanged_extern(_ jsObject: Int32, _ valueBytes: Int32, _ valueLength: Int32) -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func _extern_onValueChanged(_ jsObject: Int32, _ valueBytes: Int32, _ valueLength: Int32) -> Void { - return _extern_onValueChanged_extern(jsObject, valueBytes, valueLength) +@inline(never) fileprivate func bjs_MyViewControllerDelegate_onValueChanged(_ jsObject: Int32, _ valueBytes: Int32, _ valueLength: Int32) -> Void { + return bjs_MyViewControllerDelegate_onValueChanged_extern(jsObject, valueBytes, valueLength) } #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_onCountUpdated") -fileprivate func _extern_onCountUpdated_extern(_ jsObject: Int32, _ count: Int32) -> Int32 +fileprivate func bjs_MyViewControllerDelegate_onCountUpdated_extern(_ jsObject: Int32, _ count: Int32) -> Int32 #else -fileprivate func _extern_onCountUpdated_extern(_ jsObject: Int32, _ count: Int32) -> Int32 { +fileprivate func bjs_MyViewControllerDelegate_onCountUpdated_extern(_ jsObject: Int32, _ count: Int32) -> Int32 { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func _extern_onCountUpdated(_ jsObject: Int32, _ count: Int32) -> Int32 { - return _extern_onCountUpdated_extern(jsObject, count) +@inline(never) fileprivate func bjs_MyViewControllerDelegate_onCountUpdated(_ jsObject: Int32, _ count: Int32) -> Int32 { + return bjs_MyViewControllerDelegate_onCountUpdated_extern(jsObject, count) } #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_onLabelUpdated") -fileprivate func _extern_onLabelUpdated_extern(_ jsObject: Int32, _ prefixBytes: Int32, _ prefixLength: Int32, _ suffixBytes: Int32, _ suffixLength: Int32) -> Void +fileprivate func bjs_MyViewControllerDelegate_onLabelUpdated_extern(_ jsObject: Int32, _ prefixBytes: Int32, _ prefixLength: Int32, _ suffixBytes: Int32, _ suffixLength: Int32) -> Void #else -fileprivate func _extern_onLabelUpdated_extern(_ jsObject: Int32, _ prefixBytes: Int32, _ prefixLength: Int32, _ suffixBytes: Int32, _ suffixLength: Int32) -> Void { +fileprivate func bjs_MyViewControllerDelegate_onLabelUpdated_extern(_ jsObject: Int32, _ prefixBytes: Int32, _ prefixLength: Int32, _ suffixBytes: Int32, _ suffixLength: Int32) -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func _extern_onLabelUpdated(_ jsObject: Int32, _ prefixBytes: Int32, _ prefixLength: Int32, _ suffixBytes: Int32, _ suffixLength: Int32) -> Void { - return _extern_onLabelUpdated_extern(jsObject, prefixBytes, prefixLength, suffixBytes, suffixLength) +@inline(never) fileprivate func bjs_MyViewControllerDelegate_onLabelUpdated(_ jsObject: Int32, _ prefixBytes: Int32, _ prefixLength: Int32, _ suffixBytes: Int32, _ suffixLength: Int32) -> Void { + return bjs_MyViewControllerDelegate_onLabelUpdated_extern(jsObject, prefixBytes, prefixLength, suffixBytes, suffixLength) } #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_isCountEven") -fileprivate func _extern_isCountEven_extern(_ jsObject: Int32) -> Int32 +fileprivate func bjs_MyViewControllerDelegate_isCountEven_extern(_ jsObject: Int32) -> Int32 #else -fileprivate func _extern_isCountEven_extern(_ jsObject: Int32) -> Int32 { +fileprivate func bjs_MyViewControllerDelegate_isCountEven_extern(_ jsObject: Int32) -> Int32 { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func _extern_isCountEven(_ jsObject: Int32) -> Int32 { - return _extern_isCountEven_extern(jsObject) +@inline(never) fileprivate func bjs_MyViewControllerDelegate_isCountEven(_ jsObject: Int32) -> Int32 { + return bjs_MyViewControllerDelegate_isCountEven_extern(jsObject) } #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_onHelperUpdated") -fileprivate func _extern_onHelperUpdated_extern(_ jsObject: Int32, _ helper: UnsafeMutableRawPointer) -> Void +fileprivate func bjs_MyViewControllerDelegate_onHelperUpdated_extern(_ jsObject: Int32, _ helper: UnsafeMutableRawPointer) -> Void #else -fileprivate func _extern_onHelperUpdated_extern(_ jsObject: Int32, _ helper: UnsafeMutableRawPointer) -> Void { +fileprivate func bjs_MyViewControllerDelegate_onHelperUpdated_extern(_ jsObject: Int32, _ helper: UnsafeMutableRawPointer) -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func _extern_onHelperUpdated(_ jsObject: Int32, _ helper: UnsafeMutableRawPointer) -> Void { - return _extern_onHelperUpdated_extern(jsObject, helper) +@inline(never) fileprivate func bjs_MyViewControllerDelegate_onHelperUpdated(_ jsObject: Int32, _ helper: UnsafeMutableRawPointer) -> Void { + return bjs_MyViewControllerDelegate_onHelperUpdated_extern(jsObject, helper) } #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_createHelper") -fileprivate func _extern_createHelper_extern(_ jsObject: Int32) -> UnsafeMutableRawPointer +fileprivate func bjs_MyViewControllerDelegate_createHelper_extern(_ jsObject: Int32) -> UnsafeMutableRawPointer #else -fileprivate func _extern_createHelper_extern(_ jsObject: Int32) -> UnsafeMutableRawPointer { +fileprivate func bjs_MyViewControllerDelegate_createHelper_extern(_ jsObject: Int32) -> UnsafeMutableRawPointer { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func _extern_createHelper(_ jsObject: Int32) -> UnsafeMutableRawPointer { - return _extern_createHelper_extern(jsObject) +@inline(never) fileprivate func bjs_MyViewControllerDelegate_createHelper(_ jsObject: Int32) -> UnsafeMutableRawPointer { + return bjs_MyViewControllerDelegate_createHelper_extern(jsObject) } #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_onOptionalHelperUpdated") -fileprivate func _extern_onOptionalHelperUpdated_extern(_ jsObject: Int32, _ helperIsSome: Int32, _ helperPointer: UnsafeMutableRawPointer) -> Void +fileprivate func bjs_MyViewControllerDelegate_onOptionalHelperUpdated_extern(_ jsObject: Int32, _ helperIsSome: Int32, _ helperPointer: UnsafeMutableRawPointer) -> Void #else -fileprivate func _extern_onOptionalHelperUpdated_extern(_ jsObject: Int32, _ helperIsSome: Int32, _ helperPointer: UnsafeMutableRawPointer) -> Void { +fileprivate func bjs_MyViewControllerDelegate_onOptionalHelperUpdated_extern(_ jsObject: Int32, _ helperIsSome: Int32, _ helperPointer: UnsafeMutableRawPointer) -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func _extern_onOptionalHelperUpdated(_ jsObject: Int32, _ helperIsSome: Int32, _ helperPointer: UnsafeMutableRawPointer) -> Void { - return _extern_onOptionalHelperUpdated_extern(jsObject, helperIsSome, helperPointer) +@inline(never) fileprivate func bjs_MyViewControllerDelegate_onOptionalHelperUpdated(_ jsObject: Int32, _ helperIsSome: Int32, _ helperPointer: UnsafeMutableRawPointer) -> Void { + return bjs_MyViewControllerDelegate_onOptionalHelperUpdated_extern(jsObject, helperIsSome, helperPointer) } #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_createOptionalHelper") -fileprivate func _extern_createOptionalHelper_extern(_ jsObject: Int32) -> UnsafeMutableRawPointer +fileprivate func bjs_MyViewControllerDelegate_createOptionalHelper_extern(_ jsObject: Int32) -> UnsafeMutableRawPointer #else -fileprivate func _extern_createOptionalHelper_extern(_ jsObject: Int32) -> UnsafeMutableRawPointer { +fileprivate func bjs_MyViewControllerDelegate_createOptionalHelper_extern(_ jsObject: Int32) -> UnsafeMutableRawPointer { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func _extern_createOptionalHelper(_ jsObject: Int32) -> UnsafeMutableRawPointer { - return _extern_createOptionalHelper_extern(jsObject) +@inline(never) fileprivate func bjs_MyViewControllerDelegate_createOptionalHelper(_ jsObject: Int32) -> UnsafeMutableRawPointer { + return bjs_MyViewControllerDelegate_createOptionalHelper_extern(jsObject) } #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_createEnum") -fileprivate func _extern_createEnum_extern(_ jsObject: Int32) -> Int32 +fileprivate func bjs_MyViewControllerDelegate_createEnum_extern(_ jsObject: Int32) -> Int32 #else -fileprivate func _extern_createEnum_extern(_ jsObject: Int32) -> Int32 { +fileprivate func bjs_MyViewControllerDelegate_createEnum_extern(_ jsObject: Int32) -> Int32 { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func _extern_createEnum(_ jsObject: Int32) -> Int32 { - return _extern_createEnum_extern(jsObject) +@inline(never) fileprivate func bjs_MyViewControllerDelegate_createEnum(_ jsObject: Int32) -> Int32 { + return bjs_MyViewControllerDelegate_createEnum_extern(jsObject) } #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_handleResult") -fileprivate func _extern_handleResult_extern(_ jsObject: Int32, _ result: Int32) -> Void +fileprivate func bjs_MyViewControllerDelegate_handleResult_extern(_ jsObject: Int32, _ result: Int32) -> Void #else -fileprivate func _extern_handleResult_extern(_ jsObject: Int32, _ result: Int32) -> Void { +fileprivate func bjs_MyViewControllerDelegate_handleResult_extern(_ jsObject: Int32, _ result: Int32) -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func _extern_handleResult(_ jsObject: Int32, _ result: Int32) -> Void { - return _extern_handleResult_extern(jsObject, result) +@inline(never) fileprivate func bjs_MyViewControllerDelegate_handleResult(_ jsObject: Int32, _ result: Int32) -> Void { + return bjs_MyViewControllerDelegate_handleResult_extern(jsObject, result) } #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_getResult") -fileprivate func _extern_getResult_extern(_ jsObject: Int32) -> Int32 +fileprivate func bjs_MyViewControllerDelegate_getResult_extern(_ jsObject: Int32) -> Int32 #else -fileprivate func _extern_getResult_extern(_ jsObject: Int32) -> Int32 { +fileprivate func bjs_MyViewControllerDelegate_getResult_extern(_ jsObject: Int32) -> Int32 { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func _extern_getResult(_ jsObject: Int32) -> Int32 { - return _extern_getResult_extern(jsObject) +@inline(never) fileprivate func bjs_MyViewControllerDelegate_getResult(_ jsObject: Int32) -> Int32 { + return bjs_MyViewControllerDelegate_getResult_extern(jsObject) } #if arch(wasm32) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ProtocolInClosure.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ProtocolInClosure.swift index f02cd4019..bc63b1f65 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ProtocolInClosure.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ProtocolInClosure.swift @@ -257,14 +257,16 @@ public func _invoke_swift_closure_TestModule_10TestModuley_10RenderableP(_ boxPt #endif } -struct AnyRenderable: Renderable, _BridgedSwiftProtocolWrapper { - let jsObject: JSObject - +extension Renderable where Self: _BridgedSwiftProtocolWrapper { func render() -> String { let jsObjectValue = jsObject.bridgeJSLowerParameter() - let ret = _extern_render(jsObjectValue) + let ret = bjs_Renderable_render(jsObjectValue) return String.bridgeJSLiftReturn(ret) } +} + +struct AnyRenderable: Renderable, _BridgedSwiftProtocolWrapper { + let jsObject: JSObject static func bridgeJSLiftParameter(_ value: Int32) -> Self { return AnyRenderable(jsObject: JSObject(id: UInt32(bitPattern: value))) @@ -273,14 +275,14 @@ struct AnyRenderable: Renderable, _BridgedSwiftProtocolWrapper { #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_Renderable_render") -fileprivate func _extern_render_extern(_ jsObject: Int32) -> Int32 +fileprivate func bjs_Renderable_render_extern(_ jsObject: Int32) -> Int32 #else -fileprivate func _extern_render_extern(_ jsObject: Int32) -> Int32 { +fileprivate func bjs_Renderable_render_extern(_ jsObject: Int32) -> Int32 { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func _extern_render(_ jsObject: Int32) -> Int32 { - return _extern_render_extern(jsObject) +@inline(never) fileprivate func bjs_Renderable_render(_ jsObject: Int32) -> Int32 { + return bjs_Renderable_render_extern(jsObject) } @_expose(wasm, "bjs_processRenderable") diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GenericImports.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GenericImports.d.ts index 026713ce3..8ff2aad15 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GenericImports.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GenericImports.d.ts @@ -4,6 +4,17 @@ // To update this file, just rebuild your project or run // `swift package bridge-js`. +export interface GenericReadable { + read(): number; +} + +export interface GenericWritable { + value: number; +} + +export interface GenericNode extends GenericReadable, GenericWritable { +} + export const GenericColorValues: { readonly Red: 0; readonly Green: 1; @@ -53,6 +64,9 @@ export interface GenericConsumer { accept(value: T): void; identity(value: T): T; } +export interface ConstrainedConsumer { + accept(value: T): T; +} export type Exports = { GenericColor: GenericColorObject GenericMode: GenericModeObject @@ -70,6 +84,8 @@ export type Imports = { importGenericOptional(value: T | null): T | null; importGenericDictionary(values: Record): Record; importGenericAfterOptionalArray(values: number[] | null, value: T): T; + constrainedRoundTrip(value: T): T; + constrainedComposition(value: T): T; GenericPairFactory: { new(tag: string, first: T, second: U): GenericPairFactory; } @@ -77,6 +93,10 @@ export type Imports = { new(value: T): GenericConsumer; box(value: T): T; } + ConstrainedConsumer: { + new(value: T): ConstrainedConsumer; + identity(value: T): T; + } } export function createInstantiator(options: { imports: Imports; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GenericImports.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GenericImports.js index d8b1fdf15..529f1772e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GenericImports.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GenericImports.js @@ -428,6 +428,30 @@ export async function createInstantiator(options, swift) { return enumValue; }, }; + const __bjs_codec_M10TestModuleT15GenericReadable = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + const __bjs_codec_M10TestModuleT11GenericNode = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; const __bjs_createStructHelpers_M10TestModuleT12GenericPoint = () => ({ lower: (value) => { @@ -586,6 +610,8 @@ export async function createInstantiator(options, swift) { __bjs_codec_M10TestModuleT12GenericColor, __bjs_stringCodec, __bjs_codec_M10TestModuleT13GenericTagged, + __bjs_codec_M10TestModuleT15GenericReadable, + __bjs_codec_M10TestModuleT11GenericNode, ]; const typeIds = new Int32Array(memory.buffer, base >>> 0, count >>> 0); for (let i = 0; i < count; i++) { @@ -783,6 +809,26 @@ export async function createInstantiator(options, swift) { setException(error); } } + TestModule["bjs_constrainedRoundTrip"] = function bjs_constrainedRoundTrip(tTypeId) { + try { + const codecT = __bjs_codecForTypeId(tTypeId); + const value = codecT.lift(); + let ret = imports.constrainedRoundTrip(value); + codecT.lower(ret); + } catch (error) { + setException(error); + } + } + TestModule["bjs_constrainedComposition"] = function bjs_constrainedComposition(tTypeId) { + try { + const codecT = __bjs_codecForTypeId(tTypeId); + const value = codecT.lift(); + let ret = imports.constrainedComposition(value); + codecT.lower(ret); + } catch (error) { + setException(error); + } + } TestModule["bjs_GenericPairFactory_init"] = function bjs_GenericPairFactory_init(tagBytes, tagCount, tTypeId, uTypeId) { try { const codecT = __bjs_codecForTypeId(tTypeId); @@ -835,6 +881,61 @@ export async function createInstantiator(options, swift) { setException(error); } } + TestModule["bjs_ConstrainedConsumer_init"] = function bjs_ConstrainedConsumer_init(tTypeId) { + try { + const codecT = __bjs_codecForTypeId(tTypeId); + const value = codecT.lift(); + return swift.memory.retain(new imports.ConstrainedConsumer(value)); + } catch (error) { + setException(error); + return 0 + } + } + TestModule["bjs_ConstrainedConsumer_identity_static"] = function bjs_ConstrainedConsumer_identity_static(tTypeId) { + try { + const codecT = __bjs_codecForTypeId(tTypeId); + const value = codecT.lift(); + let ret = imports.ConstrainedConsumer.identity(value); + codecT.lower(ret); + } catch (error) { + setException(error); + } + } + TestModule["bjs_ConstrainedConsumer_accept"] = function bjs_ConstrainedConsumer_accept(self, tTypeId) { + try { + const codecT = __bjs_codecForTypeId(tTypeId); + const value = codecT.lift(); + let ret = swift.memory.getObject(self).accept(value); + codecT.lower(ret); + } catch (error) { + setException(error); + } + } + TestModule["bjs_GenericReadable_read"] = function bjs_GenericReadable_read(self) { + try { + let ret = swift.memory.getObject(self).read(); + return ret; + } catch (error) { + setException(error); + return 0 + } + } + TestModule["bjs_GenericWritable_value_get"] = function bjs_GenericWritable_value_get(self) { + try { + let ret = swift.memory.getObject(self).value; + return ret; + } catch (error) { + setException(error); + return 0 + } + } + TestModule["bjs_GenericWritable_value_set"] = function bjs_GenericWritable_value_set(self, value) { + try { + swift.memory.getObject(self).value = value; + } catch (error) { + setException(error); + } + } }, setInstance: (i) => { instance = i; diff --git a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Protocols.md b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Protocols.md index d62d71051..4c91ba749 100644 --- a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Protocols.md +++ b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Protocols.md @@ -15,6 +15,8 @@ When you mark a protocol with `@JS`, BridgeJS generates: Use `@JS("PublicName")` on a protocol to rename its TypeScript interface and generated type references. Swift still uses the original protocol name for conformances and signatures. JavaScript objects still satisfy the interface structurally; renaming does not create a protocol constructor or change how callbacks and protocol values cross the boundary. Unlike `@JS(as: Other.self)`, it does not change the representation, and combining the two options is not supported. +An `@JS` protocol can refine other `@JS` protocols declared in the same module. Its generated TypeScript interface and Swift wrapper expose inherited methods and properties. Cross-module protocol refinement is not supported. + ## Example: Counter Protocol Mark a Swift protocol with `@JS` to expose it: @@ -220,8 +222,10 @@ struct AnyCounter: Counter, _BridgedSwiftProtocolWrapper { | Optional properties | ✅ | | Optional protocol methods | ❌ | | Associated types | ❌ | -| Protocol inheritance | ❌ | -| Protocol composition: `Protocol1 & Protocol2` | ❌ | -| Generics | ❌ | +| Same-module `@JS` protocol inheritance | ✅ | +| Cross-module protocol inheritance | ❌ | +| Existential protocol composition: `any Protocol1 & Protocol2` | ❌ | +| Generic requirements | ❌ | +| Protocol-valued properties, parameters, or results in requirements | ❌ | -> Note: Protocol type support matches that of regular `@JS func` and `@JS class` exports. See , , and for more information. +> Note: For supported requirement types, see , , and . diff --git a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Importing-JavaScript/Importing-JS-Function.md b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Importing-JavaScript/Importing-JS-Function.md index ebc9ac857..02f0a349d 100644 --- a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Importing-JavaScript/Importing-JS-Function.md +++ b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Importing-JavaScript/Importing-JS-Function.md @@ -89,6 +89,17 @@ let user: User = try parse(jsonString) // T inferred from the call site `T` can be any supported primitive, `String`, `JSValue`, or a `@JS` struct, `@JS` enum, or `final @JS class` (see ), used bare or wrapped as `[T]`, `T?`, or `[String: T]`. A function may declare multiple type parameters, and a return-only generic (`func make() -> T`) works too. Generic initializers, methods, and static methods on `@JSClass` types are supported the same way. `async` generic functions and `where` clauses are not supported. +Generic imports can also constrain `T` to `@JS` protocols, as in `T: BridgedSwiftGenericBridgeable & P & Q`. If `P` inherits `BridgedSwiftGenericBridgeable`, use `T: P`: + +```swift +import JavaScriptKit + +@JS protocol Named: BridgedSwiftGenericBridgeable { var name: String { get } } +@JSFunction func display(_ value: T) throws(JSException) +``` + +Constraints may use `@JS` protocols from dependency modules, including qualified names such as `T: BridgedSwiftGenericBridgeable & Models.Named`. Concrete conformers must expose the required members to JavaScript too, including marking methods with `@JS`. This does not enable existential compositions such as `any P & Q`; the generic-import limitations above still apply. + ## Supported features | Feature | Status | @@ -96,4 +107,5 @@ let user: User = try parse(jsonString) // T inferred from the call site | Primitive parameter/result types (e.g. `Double`, `Bool`) | ✅ | | `String` parameter/result type | ✅ | | Generic parameter/result types (constrained to `BridgedSwiftGenericBridgeable`) | ✅ | +| `@JS` protocol constraints on generic imports | ✅ | | Async function | ❌ | diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift index 4496316e7..acb3e23f1 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift @@ -4247,9 +4247,7 @@ public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsy_y #endif } -struct AnyArrayElementProtocol: ArrayElementProtocol, _BridgedSwiftProtocolWrapper { - let jsObject: JSObject - +extension ArrayElementProtocol where Self: _BridgedSwiftProtocolWrapper { var value: Int { get { let jsObjectValue = jsObject.bridgeJSLowerParameter() @@ -4262,6 +4260,10 @@ struct AnyArrayElementProtocol: ArrayElementProtocol, _BridgedSwiftProtocolWrapp bjs_ArrayElementProtocol_value_set(jsObjectValue, newValueValue) } } +} + +struct AnyArrayElementProtocol: ArrayElementProtocol, _BridgedSwiftProtocolWrapper { + let jsObject: JSObject static func bridgeJSLiftParameter(_ value: Int32) -> Self { return AnyArrayElementProtocol(jsObject: JSObject(id: UInt32(bitPattern: value))) @@ -4292,18 +4294,16 @@ fileprivate func bjs_ArrayElementProtocol_value_set_extern(_ jsObject: Int32, _ return bjs_ArrayElementProtocol_value_set_extern(jsObject, newValue) } -struct AnyDataProcessor: DataProcessor, _BridgedSwiftProtocolWrapper { - let jsObject: JSObject - +extension DataProcessor where Self: _BridgedSwiftProtocolWrapper { func increment(by amount: Int) -> Void { let amountValue = amount.bridgeJSLowerParameter() let jsObjectValue = jsObject.bridgeJSLowerParameter() - _extern_increment(jsObjectValue, amountValue) + bjs_DataProcessor_increment(jsObjectValue, amountValue) } func getValue() -> Int { let jsObjectValue = jsObject.bridgeJSLowerParameter() - let ret = _extern_getValue(jsObjectValue) + let ret = bjs_DataProcessor_getValue(jsObjectValue) return Int.bridgeJSLiftReturn(ret) } @@ -4311,58 +4311,58 @@ struct AnyDataProcessor: DataProcessor, _BridgedSwiftProtocolWrapper { labelPrefix.bridgeJSWithLoweredParameter { (labelPrefixBytes, labelPrefixLength) in labelSuffix.bridgeJSWithLoweredParameter { (labelSuffixBytes, labelSuffixLength) in let jsObjectValue = jsObject.bridgeJSLowerParameter() - _extern_setLabelElements(jsObjectValue, labelPrefixBytes, labelPrefixLength, labelSuffixBytes, labelSuffixLength) + bjs_DataProcessor_setLabelElements(jsObjectValue, labelPrefixBytes, labelPrefixLength, labelSuffixBytes, labelSuffixLength) } } } func getLabel() -> String { let jsObjectValue = jsObject.bridgeJSLowerParameter() - let ret = _extern_getLabel(jsObjectValue) + let ret = bjs_DataProcessor_getLabel(jsObjectValue) return String.bridgeJSLiftReturn(ret) } func isEven() -> Bool { let jsObjectValue = jsObject.bridgeJSLowerParameter() - let ret = _extern_isEven(jsObjectValue) + let ret = bjs_DataProcessor_isEven(jsObjectValue) return Bool.bridgeJSLiftReturn(ret) } func processGreeter(_ greeter: Greeter) -> String { let greeterPointer = greeter.bridgeJSLowerParameter() let jsObjectValue = jsObject.bridgeJSLowerParameter() - let ret = _extern_processGreeter(jsObjectValue, greeterPointer) + let ret = bjs_DataProcessor_processGreeter(jsObjectValue, greeterPointer) return String.bridgeJSLiftReturn(ret) } func createGreeter() -> Greeter { let jsObjectValue = jsObject.bridgeJSLowerParameter() - let ret = _extern_createGreeter(jsObjectValue) + let ret = bjs_DataProcessor_createGreeter(jsObjectValue) return Greeter.bridgeJSLiftReturn(ret) } func processOptionalGreeter(_ greeter: Optional) -> String { let (greeterIsSome, greeterPointer) = greeter.bridgeJSLowerParameter() let jsObjectValue = jsObject.bridgeJSLowerParameter() - let ret = _extern_processOptionalGreeter(jsObjectValue, greeterIsSome, greeterPointer) + let ret = bjs_DataProcessor_processOptionalGreeter(jsObjectValue, greeterIsSome, greeterPointer) return String.bridgeJSLiftReturn(ret) } func createOptionalGreeter() -> Optional { let jsObjectValue = jsObject.bridgeJSLowerParameter() - let ret = _extern_createOptionalGreeter(jsObjectValue) + let ret = bjs_DataProcessor_createOptionalGreeter(jsObjectValue) return Optional.bridgeJSLiftReturn(ret) } func handleAPIResult(_ result: Optional) -> Void { let (resultIsSome, resultCaseId) = result.bridgeJSLowerParameter() let jsObjectValue = jsObject.bridgeJSLowerParameter() - _extern_handleAPIResult(jsObjectValue, resultIsSome, resultCaseId) + bjs_DataProcessor_handleAPIResult(jsObjectValue, resultIsSome, resultCaseId) } func getAPIResult() -> Optional { let jsObjectValue = jsObject.bridgeJSLowerParameter() - let ret = _extern_getAPIResult(jsObjectValue) + let ret = bjs_DataProcessor_getAPIResult(jsObjectValue) return Optional.bridgeJSLiftReturn(ret) } @@ -4492,6 +4492,10 @@ struct AnyDataProcessor: DataProcessor, _BridgedSwiftProtocolWrapper { bjs_DataProcessor_optionalHelper_set(jsObjectValue, newValueIsSome, newValuePointer) } } +} + +struct AnyDataProcessor: DataProcessor, _BridgedSwiftProtocolWrapper { + let jsObject: JSObject static func bridgeJSLiftParameter(_ value: Int32) -> Self { return AnyDataProcessor(jsObject: JSObject(id: UInt32(bitPattern: value))) @@ -4500,134 +4504,134 @@ struct AnyDataProcessor: DataProcessor, _BridgedSwiftProtocolWrapper { #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_increment") -fileprivate func _extern_increment_extern(_ jsObject: Int32, _ amount: Int32) -> Void +fileprivate func bjs_DataProcessor_increment_extern(_ jsObject: Int32, _ amount: Int32) -> Void #else -fileprivate func _extern_increment_extern(_ jsObject: Int32, _ amount: Int32) -> Void { +fileprivate func bjs_DataProcessor_increment_extern(_ jsObject: Int32, _ amount: Int32) -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func _extern_increment(_ jsObject: Int32, _ amount: Int32) -> Void { - return _extern_increment_extern(jsObject, amount) +@inline(never) fileprivate func bjs_DataProcessor_increment(_ jsObject: Int32, _ amount: Int32) -> Void { + return bjs_DataProcessor_increment_extern(jsObject, amount) } #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_getValue") -fileprivate func _extern_getValue_extern(_ jsObject: Int32) -> Int32 +fileprivate func bjs_DataProcessor_getValue_extern(_ jsObject: Int32) -> Int32 #else -fileprivate func _extern_getValue_extern(_ jsObject: Int32) -> Int32 { +fileprivate func bjs_DataProcessor_getValue_extern(_ jsObject: Int32) -> Int32 { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func _extern_getValue(_ jsObject: Int32) -> Int32 { - return _extern_getValue_extern(jsObject) +@inline(never) fileprivate func bjs_DataProcessor_getValue(_ jsObject: Int32) -> Int32 { + return bjs_DataProcessor_getValue_extern(jsObject) } #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_setLabelElements") -fileprivate func _extern_setLabelElements_extern(_ jsObject: Int32, _ labelPrefixBytes: Int32, _ labelPrefixLength: Int32, _ labelSuffixBytes: Int32, _ labelSuffixLength: Int32) -> Void +fileprivate func bjs_DataProcessor_setLabelElements_extern(_ jsObject: Int32, _ labelPrefixBytes: Int32, _ labelPrefixLength: Int32, _ labelSuffixBytes: Int32, _ labelSuffixLength: Int32) -> Void #else -fileprivate func _extern_setLabelElements_extern(_ jsObject: Int32, _ labelPrefixBytes: Int32, _ labelPrefixLength: Int32, _ labelSuffixBytes: Int32, _ labelSuffixLength: Int32) -> Void { +fileprivate func bjs_DataProcessor_setLabelElements_extern(_ jsObject: Int32, _ labelPrefixBytes: Int32, _ labelPrefixLength: Int32, _ labelSuffixBytes: Int32, _ labelSuffixLength: Int32) -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func _extern_setLabelElements(_ jsObject: Int32, _ labelPrefixBytes: Int32, _ labelPrefixLength: Int32, _ labelSuffixBytes: Int32, _ labelSuffixLength: Int32) -> Void { - return _extern_setLabelElements_extern(jsObject, labelPrefixBytes, labelPrefixLength, labelSuffixBytes, labelSuffixLength) +@inline(never) fileprivate func bjs_DataProcessor_setLabelElements(_ jsObject: Int32, _ labelPrefixBytes: Int32, _ labelPrefixLength: Int32, _ labelSuffixBytes: Int32, _ labelSuffixLength: Int32) -> Void { + return bjs_DataProcessor_setLabelElements_extern(jsObject, labelPrefixBytes, labelPrefixLength, labelSuffixBytes, labelSuffixLength) } #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_getLabel") -fileprivate func _extern_getLabel_extern(_ jsObject: Int32) -> Int32 +fileprivate func bjs_DataProcessor_getLabel_extern(_ jsObject: Int32) -> Int32 #else -fileprivate func _extern_getLabel_extern(_ jsObject: Int32) -> Int32 { +fileprivate func bjs_DataProcessor_getLabel_extern(_ jsObject: Int32) -> Int32 { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func _extern_getLabel(_ jsObject: Int32) -> Int32 { - return _extern_getLabel_extern(jsObject) +@inline(never) fileprivate func bjs_DataProcessor_getLabel(_ jsObject: Int32) -> Int32 { + return bjs_DataProcessor_getLabel_extern(jsObject) } #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_isEven") -fileprivate func _extern_isEven_extern(_ jsObject: Int32) -> Int32 +fileprivate func bjs_DataProcessor_isEven_extern(_ jsObject: Int32) -> Int32 #else -fileprivate func _extern_isEven_extern(_ jsObject: Int32) -> Int32 { +fileprivate func bjs_DataProcessor_isEven_extern(_ jsObject: Int32) -> Int32 { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func _extern_isEven(_ jsObject: Int32) -> Int32 { - return _extern_isEven_extern(jsObject) +@inline(never) fileprivate func bjs_DataProcessor_isEven(_ jsObject: Int32) -> Int32 { + return bjs_DataProcessor_isEven_extern(jsObject) } #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_processGreeter") -fileprivate func _extern_processGreeter_extern(_ jsObject: Int32, _ greeter: UnsafeMutableRawPointer) -> Int32 +fileprivate func bjs_DataProcessor_processGreeter_extern(_ jsObject: Int32, _ greeter: UnsafeMutableRawPointer) -> Int32 #else -fileprivate func _extern_processGreeter_extern(_ jsObject: Int32, _ greeter: UnsafeMutableRawPointer) -> Int32 { +fileprivate func bjs_DataProcessor_processGreeter_extern(_ jsObject: Int32, _ greeter: UnsafeMutableRawPointer) -> Int32 { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func _extern_processGreeter(_ jsObject: Int32, _ greeter: UnsafeMutableRawPointer) -> Int32 { - return _extern_processGreeter_extern(jsObject, greeter) +@inline(never) fileprivate func bjs_DataProcessor_processGreeter(_ jsObject: Int32, _ greeter: UnsafeMutableRawPointer) -> Int32 { + return bjs_DataProcessor_processGreeter_extern(jsObject, greeter) } #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_createGreeter") -fileprivate func _extern_createGreeter_extern(_ jsObject: Int32) -> UnsafeMutableRawPointer +fileprivate func bjs_DataProcessor_createGreeter_extern(_ jsObject: Int32) -> UnsafeMutableRawPointer #else -fileprivate func _extern_createGreeter_extern(_ jsObject: Int32) -> UnsafeMutableRawPointer { +fileprivate func bjs_DataProcessor_createGreeter_extern(_ jsObject: Int32) -> UnsafeMutableRawPointer { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func _extern_createGreeter(_ jsObject: Int32) -> UnsafeMutableRawPointer { - return _extern_createGreeter_extern(jsObject) +@inline(never) fileprivate func bjs_DataProcessor_createGreeter(_ jsObject: Int32) -> UnsafeMutableRawPointer { + return bjs_DataProcessor_createGreeter_extern(jsObject) } #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_processOptionalGreeter") -fileprivate func _extern_processOptionalGreeter_extern(_ jsObject: Int32, _ greeterIsSome: Int32, _ greeterPointer: UnsafeMutableRawPointer) -> Int32 +fileprivate func bjs_DataProcessor_processOptionalGreeter_extern(_ jsObject: Int32, _ greeterIsSome: Int32, _ greeterPointer: UnsafeMutableRawPointer) -> Int32 #else -fileprivate func _extern_processOptionalGreeter_extern(_ jsObject: Int32, _ greeterIsSome: Int32, _ greeterPointer: UnsafeMutableRawPointer) -> Int32 { +fileprivate func bjs_DataProcessor_processOptionalGreeter_extern(_ jsObject: Int32, _ greeterIsSome: Int32, _ greeterPointer: UnsafeMutableRawPointer) -> Int32 { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func _extern_processOptionalGreeter(_ jsObject: Int32, _ greeterIsSome: Int32, _ greeterPointer: UnsafeMutableRawPointer) -> Int32 { - return _extern_processOptionalGreeter_extern(jsObject, greeterIsSome, greeterPointer) +@inline(never) fileprivate func bjs_DataProcessor_processOptionalGreeter(_ jsObject: Int32, _ greeterIsSome: Int32, _ greeterPointer: UnsafeMutableRawPointer) -> Int32 { + return bjs_DataProcessor_processOptionalGreeter_extern(jsObject, greeterIsSome, greeterPointer) } #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_createOptionalGreeter") -fileprivate func _extern_createOptionalGreeter_extern(_ jsObject: Int32) -> UnsafeMutableRawPointer +fileprivate func bjs_DataProcessor_createOptionalGreeter_extern(_ jsObject: Int32) -> UnsafeMutableRawPointer #else -fileprivate func _extern_createOptionalGreeter_extern(_ jsObject: Int32) -> UnsafeMutableRawPointer { +fileprivate func bjs_DataProcessor_createOptionalGreeter_extern(_ jsObject: Int32) -> UnsafeMutableRawPointer { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func _extern_createOptionalGreeter(_ jsObject: Int32) -> UnsafeMutableRawPointer { - return _extern_createOptionalGreeter_extern(jsObject) +@inline(never) fileprivate func bjs_DataProcessor_createOptionalGreeter(_ jsObject: Int32) -> UnsafeMutableRawPointer { + return bjs_DataProcessor_createOptionalGreeter_extern(jsObject) } #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_handleAPIResult") -fileprivate func _extern_handleAPIResult_extern(_ jsObject: Int32, _ resultIsSome: Int32, _ resultCaseId: Int32) -> Void +fileprivate func bjs_DataProcessor_handleAPIResult_extern(_ jsObject: Int32, _ resultIsSome: Int32, _ resultCaseId: Int32) -> Void #else -fileprivate func _extern_handleAPIResult_extern(_ jsObject: Int32, _ resultIsSome: Int32, _ resultCaseId: Int32) -> Void { +fileprivate func bjs_DataProcessor_handleAPIResult_extern(_ jsObject: Int32, _ resultIsSome: Int32, _ resultCaseId: Int32) -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func _extern_handleAPIResult(_ jsObject: Int32, _ resultIsSome: Int32, _ resultCaseId: Int32) -> Void { - return _extern_handleAPIResult_extern(jsObject, resultIsSome, resultCaseId) +@inline(never) fileprivate func bjs_DataProcessor_handleAPIResult(_ jsObject: Int32, _ resultIsSome: Int32, _ resultCaseId: Int32) -> Void { + return bjs_DataProcessor_handleAPIResult_extern(jsObject, resultIsSome, resultCaseId) } #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_getAPIResult") -fileprivate func _extern_getAPIResult_extern(_ jsObject: Int32) -> Int32 +fileprivate func bjs_DataProcessor_getAPIResult_extern(_ jsObject: Int32) -> Int32 #else -fileprivate func _extern_getAPIResult_extern(_ jsObject: Int32) -> Int32 { +fileprivate func bjs_DataProcessor_getAPIResult_extern(_ jsObject: Int32) -> Int32 { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func _extern_getAPIResult(_ jsObject: Int32) -> Int32 { - return _extern_getAPIResult_extern(jsObject) +@inline(never) fileprivate func bjs_DataProcessor_getAPIResult(_ jsObject: Int32) -> Int32 { + return bjs_DataProcessor_getAPIResult_extern(jsObject) } #if arch(wasm32) @@ -4858,15 +4862,266 @@ fileprivate func bjs_DataProcessor_optionalHelper_set_extern(_ jsObject: Int32, return bjs_DataProcessor_optionalHelper_set_extern(jsObject, newValueIsSome, newValuePointer) } -struct AnyJSNameTransformer: JSNameTransformer, _BridgedSwiftProtocolWrapper { +extension GenericRTPosition where Self: _BridgedSwiftProtocolWrapper { + func sum() -> Int { + let jsObjectValue = jsObject.bridgeJSLowerParameter() + let ret = bjs_GenericRTPosition_sum(jsObjectValue) + return Int.bridgeJSLiftReturn(ret) + } + + var x: Int { + get { + let jsObjectValue = jsObject.bridgeJSLowerParameter() + let ret = bjs_GenericRTPosition_x_get(jsObjectValue) + return Int.bridgeJSLiftReturn(ret) + } + } +} + +struct AnyGenericRTPosition: GenericRTPosition, _BridgedSwiftProtocolWrapper { let jsObject: JSObject + static func bridgeJSLiftParameter(_ value: Int32) -> Self { + return AnyGenericRTPosition(jsObject: JSObject(id: UInt32(bitPattern: value))) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_GenericRTPosition_sum") +fileprivate func bjs_GenericRTPosition_sum_extern(_ jsObject: Int32) -> Int32 +#else +fileprivate func bjs_GenericRTPosition_sum_extern(_ jsObject: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_GenericRTPosition_sum(_ jsObject: Int32) -> Int32 { + return bjs_GenericRTPosition_sum_extern(jsObject) +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_GenericRTPosition_x_get") +fileprivate func bjs_GenericRTPosition_x_get_extern(_ jsObject: Int32) -> Int32 +#else +fileprivate func bjs_GenericRTPosition_x_get_extern(_ jsObject: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_GenericRTPosition_x_get(_ jsObject: Int32) -> Int32 { + return bjs_GenericRTPosition_x_get_extern(jsObject) +} + +extension GenericRTNode where Self: _BridgedSwiftProtocolWrapper { + var y: Int { + get { + let jsObjectValue = jsObject.bridgeJSLowerParameter() + let ret = bjs_GenericRTNode_y_get(jsObjectValue) + return Int.bridgeJSLiftReturn(ret) + } + } +} + +struct AnyGenericRTNode: GenericRTNode, _BridgedSwiftProtocolWrapper { + let jsObject: JSObject + + static func bridgeJSLiftParameter(_ value: Int32) -> Self { + return AnyGenericRTNode(jsObject: JSObject(id: UInt32(bitPattern: value))) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_GenericRTNode_y_get") +fileprivate func bjs_GenericRTNode_y_get_extern(_ jsObject: Int32) -> Int32 +#else +fileprivate func bjs_GenericRTNode_y_get_extern(_ jsObject: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_GenericRTNode_y_get(_ jsObject: Int32) -> Int32 { + return bjs_GenericRTNode_y_get_extern(jsObject) +} + +extension RefineIdentified where Self: _BridgedSwiftProtocolWrapper { + var id: String { + get { + let jsObjectValue = jsObject.bridgeJSLowerParameter() + let ret = bjs_RefineIdentified_id_get(jsObjectValue) + return String.bridgeJSLiftReturn(ret) + } + } + + var score: Int { + get { + let jsObjectValue = jsObject.bridgeJSLowerParameter() + let ret = bjs_RefineIdentified_score_get(jsObjectValue) + return Int.bridgeJSLiftReturn(ret) + } + set { + let newValueValue = newValue.bridgeJSLowerParameter() + let jsObjectValue = jsObject.bridgeJSLowerParameter() + bjs_RefineIdentified_score_set(jsObjectValue, newValueValue) + } + } +} + +struct AnyRefineIdentified: RefineIdentified, _BridgedSwiftProtocolWrapper { + let jsObject: JSObject + + static func bridgeJSLiftParameter(_ value: Int32) -> Self { + return AnyRefineIdentified(jsObject: JSObject(id: UInt32(bitPattern: value))) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_RefineIdentified_id_get") +fileprivate func bjs_RefineIdentified_id_get_extern(_ jsObject: Int32) -> Int32 +#else +fileprivate func bjs_RefineIdentified_id_get_extern(_ jsObject: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_RefineIdentified_id_get(_ jsObject: Int32) -> Int32 { + return bjs_RefineIdentified_id_get_extern(jsObject) +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_RefineIdentified_score_get") +fileprivate func bjs_RefineIdentified_score_get_extern(_ jsObject: Int32) -> Int32 +#else +fileprivate func bjs_RefineIdentified_score_get_extern(_ jsObject: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_RefineIdentified_score_get(_ jsObject: Int32) -> Int32 { + return bjs_RefineIdentified_score_get_extern(jsObject) +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_RefineIdentified_score_set") +fileprivate func bjs_RefineIdentified_score_set_extern(_ jsObject: Int32, _ newValue: Int32) -> Void +#else +fileprivate func bjs_RefineIdentified_score_set_extern(_ jsObject: Int32, _ newValue: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_RefineIdentified_score_set(_ jsObject: Int32, _ newValue: Int32) -> Void { + return bjs_RefineIdentified_score_set_extern(jsObject, newValue) +} + +extension RefineNamed where Self: _BridgedSwiftProtocolWrapper { + func label() -> String { + let jsObjectValue = jsObject.bridgeJSLowerParameter() + let ret = bjs_RefineNamed_label(jsObjectValue) + return String.bridgeJSLiftReturn(ret) + } + + var name: String { + get { + let jsObjectValue = jsObject.bridgeJSLowerParameter() + let ret = bjs_RefineNamed_name_get(jsObjectValue) + return String.bridgeJSLiftReturn(ret) + } + } +} + +struct AnyRefineNamed: RefineNamed, _BridgedSwiftProtocolWrapper { + let jsObject: JSObject + + static func bridgeJSLiftParameter(_ value: Int32) -> Self { + return AnyRefineNamed(jsObject: JSObject(id: UInt32(bitPattern: value))) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_RefineNamed_label") +fileprivate func bjs_RefineNamed_label_extern(_ jsObject: Int32) -> Int32 +#else +fileprivate func bjs_RefineNamed_label_extern(_ jsObject: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_RefineNamed_label(_ jsObject: Int32) -> Int32 { + return bjs_RefineNamed_label_extern(jsObject) +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_RefineNamed_name_get") +fileprivate func bjs_RefineNamed_name_get_extern(_ jsObject: Int32) -> Int32 +#else +fileprivate func bjs_RefineNamed_name_get_extern(_ jsObject: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_RefineNamed_name_get(_ jsObject: Int32) -> Int32 { + return bjs_RefineNamed_name_get_extern(jsObject) +} + +extension RefineEntity where Self: _BridgedSwiftProtocolWrapper { + func label() -> String { + let jsObjectValue = jsObject.bridgeJSLowerParameter() + let ret = bjs_RefineEntity_label(jsObjectValue) + return String.bridgeJSLiftReturn(ret) + } + + var id: String { + get { + let jsObjectValue = jsObject.bridgeJSLowerParameter() + let ret = bjs_RefineEntity_id_get(jsObjectValue) + return String.bridgeJSLiftReturn(ret) + } + } +} + +struct AnyRefineEntity: RefineEntity, _BridgedSwiftProtocolWrapper { + let jsObject: JSObject + + static func bridgeJSLiftParameter(_ value: Int32) -> Self { + return AnyRefineEntity(jsObject: JSObject(id: UInt32(bitPattern: value))) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_RefineEntity_label") +fileprivate func bjs_RefineEntity_label_extern(_ jsObject: Int32) -> Int32 +#else +fileprivate func bjs_RefineEntity_label_extern(_ jsObject: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_RefineEntity_label(_ jsObject: Int32) -> Int32 { + return bjs_RefineEntity_label_extern(jsObject) +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_RefineEntity_id_get") +fileprivate func bjs_RefineEntity_id_get_extern(_ jsObject: Int32) -> Int32 +#else +fileprivate func bjs_RefineEntity_id_get_extern(_ jsObject: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_RefineEntity_id_get(_ jsObject: Int32) -> Int32 { + return bjs_RefineEntity_id_get_extern(jsObject) +} + +struct AnyRefineTagged: RefineTagged, _BridgedSwiftProtocolWrapper { + let jsObject: JSObject + + static func bridgeJSLiftParameter(_ value: Int32) -> Self { + return AnyRefineTagged(jsObject: JSObject(id: UInt32(bitPattern: value))) + } +} + +extension JSNameTransformer where Self: _BridgedSwiftProtocolWrapper { func apply(_ value: Int) -> Int { let valueValue = value.bridgeJSLowerParameter() let jsObjectValue = jsObject.bridgeJSLowerParameter() - let ret = _extern_apply(jsObjectValue, valueValue) + let ret = bjs_JSNameTransformer_apply(jsObjectValue, valueValue) return Int.bridgeJSLiftReturn(ret) } +} + +struct AnyJSNameTransformer: JSNameTransformer, _BridgedSwiftProtocolWrapper { + let jsObject: JSObject static func bridgeJSLiftParameter(_ value: Int32) -> Self { return AnyJSNameTransformer(jsObject: JSObject(id: UInt32(bitPattern: value))) @@ -4875,14 +5130,14 @@ struct AnyJSNameTransformer: JSNameTransformer, _BridgedSwiftProtocolWrapper { #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_JSNameTransformer_apply") -fileprivate func _extern_apply_extern(_ jsObject: Int32, _ value: Int32) -> Int32 +fileprivate func bjs_JSNameTransformer_apply_extern(_ jsObject: Int32, _ value: Int32) -> Int32 #else -fileprivate func _extern_apply_extern(_ jsObject: Int32, _ value: Int32) -> Int32 { +fileprivate func bjs_JSNameTransformer_apply_extern(_ jsObject: Int32, _ value: Int32) -> Int32 { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func _extern_apply(_ jsObject: Int32, _ value: Int32) -> Int32 { - return _extern_apply_extern(jsObject, value) +@inline(never) fileprivate func bjs_JSNameTransformer_apply(_ jsObject: Int32, _ value: Int32) -> Int32 { + return bjs_JSNameTransformer_apply_extern(jsObject, value) } extension Severity: _BridgedSwiftCaseEnum { @@ -7841,6 +8096,18 @@ fileprivate func _bjs_struct_lift_GenericRTPoint_extern() -> Int32 { return _bjs_struct_lift_GenericRTPoint_extern() } +@_expose(wasm, "bjs_GenericRTPoint_sum") +@_cdecl("bjs_GenericRTPoint_sum") +public func _bjs_GenericRTPoint_sum() -> Int32 { + #if arch(wasm32) + let _self = GenericRTPoint.bridgeJSLiftParameter() + let ret = _self.sum() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + extension GenericRTNamespace.Metadata: _BridgedSwiftStruct { @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> GenericRTNamespace.Metadata { let count = Int.bridgeJSStackPop() @@ -11254,6 +11521,30 @@ public func _bjs_roundTripMessage(_ message: Int32) -> Void { #endif } +@_expose(wasm, "bjs_describeRefinedEntity") +@_cdecl("bjs_describeRefinedEntity") +public func _bjs_describeRefinedEntity(_ entity: Int32) -> Void { + #if arch(wasm32) + let entity = AnyRefineEntity.bridgeJSLiftParameter(entity) + let ret = describeRefinedEntity(_: entity) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_describeTaggedEntity") +@_cdecl("bjs_describeTaggedEntity") +public func _bjs_describeTaggedEntity(_ entity: Int32) -> Void { + #if arch(wasm32) + let entity = AnyRefineTagged.bridgeJSLiftParameter(entity) + let ret = describeTaggedEntity(_: entity) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_renamedEcho") @_cdecl("bjs_renamedEcho") public func _bjs_renamedEcho(_ valueBytes: Int32, _ valueLength: Int32) -> Void { @@ -15910,6 +16201,14 @@ extension APIOptionalResult: BridgedSwiftGenericBridgeable { @_spi(BridgeJS) public static let bridgeJSTypeHandle = APIOptionalResult.bridgeJSMakeTypeHandle() } +extension AnyGenericRTPosition: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = AnyGenericRTPosition.bridgeJSMakeTypeHandle() +} + +extension AnyGenericRTNode: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = AnyGenericRTNode.bridgeJSMakeTypeHandle() +} + @JSFunction func Promise_reject(_ promise: JSObject, _ value: JSValue) throws(JSException) #if arch(wasm32) @@ -19464,6 +19763,47 @@ func _$jsGenericThrowOrRoundTrip(_ shouldThrow return T.bridgeJSStackPop() } +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_jsGenericNodeRoundTrip") +fileprivate func bjs_jsGenericNodeRoundTrip_extern(_ _generic0TypeId: Int32) -> Void +#else +fileprivate func bjs_jsGenericNodeRoundTrip_extern(_ _generic0TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_jsGenericNodeRoundTrip(_ _generic0TypeId: Int32) -> Void { + return bjs_jsGenericNodeRoundTrip_extern(_generic0TypeId) +} + +func _$jsGenericNodeRoundTrip(_ value: T) throws(JSException) -> T { + value.bridgeJSStackPush() + bjs_jsGenericNodeRoundTrip(T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return T.bridgeJSStackPop() +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_jsGenericMakeNode") +fileprivate func bjs_jsGenericMakeNode_extern(_ _generic0TypeId: Int32) -> Void +#else +fileprivate func bjs_jsGenericMakeNode_extern(_ _generic0TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_jsGenericMakeNode(_ _generic0TypeId: Int32) -> Void { + return bjs_jsGenericMakeNode_extern(_generic0TypeId) +} + +func _$jsGenericMakeNode() throws(JSException) -> T { + bjs_jsGenericMakeNode(T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return T.bridgeJSStackPop() +} + #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_ImportGenericConsumer_init") fileprivate func bjs_ImportGenericConsumer_init_extern() -> Int32 @@ -21026,6 +21366,8 @@ public func _bjs_BridgeJSRuntimeTests_register_type_handles() { GenericRTOutcome.bridgeJSTypeID, OptionalAllTypesResult.bridgeJSTypeID, APIOptionalResult.bridgeJSTypeID, + AnyGenericRTPosition.bridgeJSTypeID, + AnyGenericRTNode.bridgeJSTypeID, ] typeIds.withUnsafeBufferPointer { buffer in _bjs_BridgeJSRuntimeTests_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json index 0084d9f6a..4749c6eb3 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json @@ -17671,6 +17671,56 @@ } } }, + { + "abiName" : "bjs_describeRefinedEntity", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "describeRefinedEntity", + "parameters" : [ + { + "label" : "_", + "name" : "entity", + "type" : { + "swiftProtocol" : { + "_0" : "RefineEntity" + } + } + } + ], + "returnType" : { + "string" : { + + } + } + }, + { + "abiName" : "bjs_describeTaggedEntity", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "describeTaggedEntity", + "parameters" : [ + { + "label" : "_", + "name" : "entity", + "type" : { + "swiftProtocol" : { + "_0" : "RefineTagged" + } + } + } + ], + "returnType" : { + "string" : { + + } + } + }, { "abiName" : "bjs_renamedEcho", "effects" : { @@ -18984,6 +19034,181 @@ } ] }, + { + "isGenericBridgeable" : true, + "methods" : [ + { + "abiName" : "bjs_GenericRTPosition_sum", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "sum", + "parameters" : [ + + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "name" : "GenericRTPosition", + "properties" : [ + { + "isReadonly" : true, + "name" : "x", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ] + }, + { + "inheritedJSProtocols" : [ + "GenericRTPosition" + ], + "isGenericBridgeable" : true, + "methods" : [ + + ], + "name" : "GenericRTNode", + "properties" : [ + { + "isReadonly" : true, + "name" : "y", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ] + }, + { + "methods" : [ + + ], + "name" : "RefineIdentified", + "properties" : [ + { + "isReadonly" : true, + "name" : "id", + "type" : { + "string" : { + + } + } + }, + { + "isReadonly" : false, + "name" : "score", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ] + }, + { + "methods" : [ + { + "abiName" : "bjs_RefineNamed_label", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "label", + "parameters" : [ + + ], + "returnType" : { + "string" : { + + } + } + } + ], + "name" : "RefineNamed", + "properties" : [ + { + "isReadonly" : true, + "name" : "name", + "type" : { + "string" : { + + } + } + } + ] + }, + { + "inheritedJSProtocols" : [ + "RefineIdentified", + "RefineNamed" + ], + "methods" : [ + { + "abiName" : "bjs_RefineEntity_label", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "label", + "parameters" : [ + + ], + "returnType" : { + "string" : { + + } + } + } + ], + "name" : "RefineEntity", + "properties" : [ + { + "isReadonly" : true, + "name" : "id", + "type" : { + "string" : { + + } + } + } + ] + }, + { + "inheritedJSProtocols" : [ + "RefineEntity" + ], + "methods" : [ + + ], + "name" : "RefineTagged", + "properties" : [ + + ] + }, { "jsName" : "CounterTransform", "methods" : [ @@ -19377,7 +19602,26 @@ }, { "methods" : [ + { + "abiName" : "bjs_GenericRTPoint_sum", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "sum", + "parameters" : [ + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } ], "name" : "GenericRTPoint", "properties" : [ @@ -25257,7 +25501,9 @@ "isThrows" : true }, "genericParameters" : [ - "T" + { + "name" : "T" + } ], "name" : "jsGenericRoundTrip", "parameters" : [ @@ -25284,7 +25530,9 @@ "isThrows" : true }, "genericParameters" : [ - "T" + { + "name" : "T" + } ], "name" : "jsGenericRoundTripClass", "parameters" : [ @@ -25311,7 +25559,9 @@ "isThrows" : true }, "genericParameters" : [ - "T" + { + "name" : "T" + } ], "name" : "jsGenericParsePoint", "parameters" : [ @@ -25338,7 +25588,9 @@ "isThrows" : true }, "genericParameters" : [ - "T" + { + "name" : "T" + } ], "name" : "jsImportPickFirst", "parameters" : [ @@ -25373,7 +25625,9 @@ "isThrows" : true }, "genericParameters" : [ - "T" + { + "name" : "T" + } ], "name" : "jsImportMakeInt", "parameters" : [ @@ -25393,8 +25647,12 @@ "isThrows" : true }, "genericParameters" : [ - "T", - "U" + { + "name" : "T" + }, + { + "name" : "U" + } ], "name" : "jsImportCombineSecond", "parameters" : [ @@ -25429,7 +25687,9 @@ "isThrows" : true }, "genericParameters" : [ - "T" + { + "name" : "T" + } ], "name" : "jsGenericArrayRoundTrip", "parameters" : [ @@ -25464,7 +25724,9 @@ "isThrows" : true }, "genericParameters" : [ - "T" + { + "name" : "T" + } ], "name" : "jsGenericOptionalRoundTrip", "parameters" : [ @@ -25501,7 +25763,9 @@ "isThrows" : true }, "genericParameters" : [ - "T" + { + "name" : "T" + } ], "name" : "jsGenericDictRoundTrip", "parameters" : [ @@ -25536,7 +25800,9 @@ "isThrows" : true }, "genericParameters" : [ - "T" + { + "name" : "T" + } ], "name" : "jsGenericAfterOptionalArray", "parameters" : [ @@ -25583,7 +25849,9 @@ "isThrows" : true }, "genericParameters" : [ - "T" + { + "name" : "T" + } ], "name" : "jsGenericThrowOrRoundTrip", "parameters" : [ @@ -25609,6 +25877,64 @@ "_0" : "T" } } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + { + "constraints" : [ + "GenericRTNode" + ], + "name" : "T" + } + ], + "name" : "jsGenericNodeRoundTrip", + "parameters" : [ + { + "name" : "value", + "type" : { + "generic" : { + "_0" : "T" + } + } + } + ], + "returnType" : { + "generic" : { + "_0" : "T" + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + { + "constraints" : [ + "GenericRTPosition", + "GenericRTNode" + ], + "name" : "T" + } + ], + "name" : "jsGenericMakeNode", + "parameters" : [ + + ], + "returnType" : { + "generic" : { + "_0" : "T" + } + } } ], "types" : [ @@ -25632,7 +25958,9 @@ "isThrows" : true }, "genericParameters" : [ - "T" + { + "name" : "T" + } ], "name" : "identity", "parameters" : [ @@ -25665,7 +25993,9 @@ "isThrows" : true }, "genericParameters" : [ - "T" + { + "name" : "T" + } ], "name" : "box", "parameters" : [ @@ -25691,7 +26021,9 @@ "constructor" : { "accessLevel" : "internal", "genericParameters" : [ - "T" + { + "name" : "T" + } ], "parameters" : [ { @@ -25716,7 +26048,9 @@ "isThrows" : true }, "genericParameters" : [ - "T" + { + "name" : "T" + } ], "name" : "unwrap", "parameters" : [ diff --git a/Tests/BridgeJSRuntimeTests/ImportGenericAPIs.swift b/Tests/BridgeJSRuntimeTests/ImportGenericAPIs.swift index bfd63839f..c5484edc6 100644 --- a/Tests/BridgeJSRuntimeTests/ImportGenericAPIs.swift +++ b/Tests/BridgeJSRuntimeTests/ImportGenericAPIs.swift @@ -79,7 +79,34 @@ import JavaScriptKit @JSFunction func unwrap() throws(JSException) -> T } +@JS protocol GenericRTPosition: BridgedSwiftGenericBridgeable { + var x: Int { get } + func sum() -> Int +} + +@JS protocol GenericRTNode: GenericRTPosition { + var y: Int { get } +} + +extension GenericRTPoint: GenericRTNode { + @JS func sum() -> Int { x + y } +} + +@JSFunction func jsGenericNodeRoundTrip(_ value: T) throws(JSException) -> T +@JSFunction func jsGenericMakeNode() + throws(JSException) -> T + @Suite struct ImportGenericAPITests { + @Test func constrainedProtocolRoundTrip() throws { + let point = try jsGenericNodeRoundTrip(GenericRTPoint(x: 1, y: 2)) + #expect(point.sum() == 3) + let node: AnyGenericRTNode = try jsGenericMakeNode() + #expect(node.x == 3) + #expect(node.y == 4) + #expect(node.sum() == 7) + #expect(try jsGenericNodeRoundTrip(node).jsObject == node.jsObject) + } + @Test func genericRoundTripScalars() throws { #expect(try jsGenericRoundTrip(42) == 42) #expect(try jsGenericRoundTrip(-7) == -7) @@ -278,3 +305,30 @@ import JavaScriptKit #expect(color == .green) } } + +@JS protocol RefineIdentified { + var id: String { get } + var score: Int { get set } +} + +@JS protocol RefineNamed { + var name: String { get } + func label() -> String +} + +@JS protocol RefineEntity: RefineIdentified, RefineNamed { + var id: String { get } + func label() -> String +} + +@JS func describeRefinedEntity(_ entity: RefineEntity) -> String { + var identified: any RefineIdentified = entity + identified.score = entity.score + 1 + return "\(entity.id):\(entity.name):\(entity.label()):\(identified.score)" +} + +@JS protocol RefineTagged: RefineEntity {} + +@JS func describeTaggedEntity(_ entity: RefineTagged) -> String { + "\(entity.id)/\(entity.name)/\(entity.score)" +} diff --git a/Tests/prelude.mjs b/Tests/prelude.mjs index 977a1f386..5287df791 100644 --- a/Tests/prelude.mjs +++ b/Tests/prelude.mjs @@ -178,6 +178,11 @@ export async function setupOptions(options, context) { jsGenericOptionalRoundTrip: (v) => v, jsGenericDictRoundTrip: (v) => v, jsGenericAfterOptionalArray: (a, b) => `${JSON.stringify(a)}|${JSON.stringify(b)}`, + jsGenericNodeRoundTrip: (value) => { + if (value.sum() !== value.x + value.y) throw new Error("Invalid protocol method result"); + return value; + }, + jsGenericMakeNode: () => ({ x: 3, y: 4, sum() { return this.x + this.y; } }), ImportGenericConsumer: class { identity(value) { return value; @@ -296,6 +301,10 @@ function BridgeJSRuntimeTests_runJsWorks(instance, exports) { const optDict = { hello: "world" }; assert.deepEqual(exports.roundTripOptionalDictionaryExport(optDict), optDict); assert.equal(exports.roundTripOptionalDictionaryExport(null), null); + const entity = { id: "e1", name: "Main", score: 10, label() { return "L" + this.score; } }; + assert.equal(exports.describeRefinedEntity(entity), "e1:Main:L11:11"); + assert.equal(entity.score, 11); + assert.equal(exports.describeTaggedEntity(entity), "e1/Main/11"); const arrayStruct = { ints: [1, 2, 3], optStrings: ["a", "b"] }; const arrayStructRoundTrip = exports.roundTripArrayMembers(arrayStruct); assert.deepEqual(arrayStructRoundTrip.ints, [1, 2, 3]);