diff --git a/Benchmarks/Sources/Generated/BridgeJS.swift b/Benchmarks/Sources/Generated/BridgeJS.swift index a19e2c53a..77fefad8a 100644 --- a/Benchmarks/Sources/Generated/BridgeJS.swift +++ b/Benchmarks/Sources/Generated/BridgeJS.swift @@ -230,11 +230,7 @@ extension Person: _BridgedSwiftStruct { self.name.bridgeJSStackPush() self.age.bridgeJSStackPush() self.address.bridgeJSStackPush() - let __bjs_isSome_email = self.email != nil - if let __bjs_unwrapped_email = self.email { - __bjs_unwrapped_email.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_email ? 1 : 0) + self.email.bridgeJSStackPush() } init(unsafelyCopying jsObject: JSObject) { @@ -1603,11 +1599,7 @@ public func _bjs_ArrayRoundtrip_makeOptionalIntArray(_ _self: UnsafeMutableRawPo #if arch(wasm32) let ret = ArrayRoundtrip.bridgeJSLiftParameter(_self).makeOptionalIntArray() for __bjs_elem_ret in ret { - let __bjs_isSome_ret_elem = __bjs_elem_ret != nil - if let __bjs_unwrapped_ret_elem = __bjs_elem_ret { - __bjs_unwrapped_ret_elem.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_ret_elem ? 1 : 0) + __bjs_elem_ret.bridgeJSStackPush() } _swift_js_push_i32(Int32(ret.count)) #else @@ -1630,11 +1622,7 @@ public func _bjs_ArrayRoundtrip_roundtripOptionalIntArray(_ _self: UnsafeMutable return __result }()) for __bjs_elem_ret in ret { - let __bjs_isSome_ret_elem = __bjs_elem_ret != nil - if let __bjs_unwrapped_ret_elem = __bjs_elem_ret { - __bjs_unwrapped_ret_elem.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_ret_elem ? 1 : 0) + __bjs_elem_ret.bridgeJSStackPush() } _swift_js_push_i32(Int32(ret.count)) #else diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift index b7c66dcd2..12d472cbe 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift @@ -824,16 +824,12 @@ struct StackCodegen { switch type { case .string, .int, .uint, .bool, .float, .double, .jsValue, .jsObject(nil), .swiftHeapObject, .unsafePointer, .closure, - .caseEnum, .rawValueEnum: + .caseEnum, .rawValueEnum, .associatedValueEnum, .swiftStruct, .nullable: return ["\(raw: accessor).bridgeJSStackPush()"] case .jsObject(_?): return ["\(raw: accessor).jsObject.bridgeJSStackPush()"] case .swiftProtocol: return ["(\(raw: accessor) as! \(raw: type.swiftType)).bridgeJSStackPush()"] - case .associatedValueEnum, .swiftStruct: - return ["\(raw: accessor).bridgeJSStackPush()"] - case .nullable(let wrappedType, _): - return lowerOptionalStatements(wrappedType: wrappedType, accessor: accessor, varPrefix: varPrefix) case .void, .namespaceEnum: return [] case .array(let elementType): @@ -946,54 +942,6 @@ struct StackCodegen { statements.append("_swift_js_push_i32(Int32(\(raw: accessor).count))") return statements } - - private func lowerOptionalStatements( - wrappedType: BridgeType, - accessor: String, - varPrefix: String - ) -> [CodeBlockItemSyntax] { - switch wrappedType { - case .array, .dictionary, .swiftStruct: - return ["\(raw: accessor).bridgeJSStackPush()"] - default: - break - } - - var statements: [String] = [] - statements.append("let __bjs_isSome_\(varPrefix) = \(accessor) != nil") - statements.append("if let __bjs_unwrapped_\(varPrefix) = \(accessor) {") - - let innerStatements = lowerUnwrappedOptionalStatements( - wrappedType: wrappedType, - unwrappedVar: "__bjs_unwrapped_\(varPrefix)" - ) - for stmt in innerStatements { - statements.append(stmt.description) - } - - statements.append("}") - statements.append("_swift_js_push_i32(__bjs_isSome_\(varPrefix) ? 1 : 0)") - let parsed: CodeBlockItemListSyntax = "\(raw: statements.joined(separator: "\n"))" - return Array(parsed) - } - - private func lowerUnwrappedOptionalStatements( - wrappedType: BridgeType, - unwrappedVar: String - ) -> [CodeBlockItemSyntax] { - switch wrappedType { - case .jsObject(_?): - return ["\(raw: unwrappedVar).jsObject.bridgeJSStackPush()"] - case .swiftProtocol: - return ["(\(raw: unwrappedVar) as! \(raw: wrappedType.swiftType)).bridgeJSStackPush()"] - case .string, .int, .uint, .bool, .float, .double, .jsValue, - .jsObject(nil), .swiftHeapObject, .unsafePointer, .closure, - .caseEnum, .rawValueEnum, .associatedValueEnum: - return ["\(raw: unwrappedVar).bridgeJSStackPush()"] - default: - return ["preconditionFailure(\"BridgeJS: unsupported optional wrapped type\")"] - } - } } // MARK: - EnumCodegen diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift index 63eb6cc0b..ba0d0d86c 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift @@ -1204,22 +1204,8 @@ struct IntrinsicJSFragment: Sendable { } } - @discardableResult - private static func emitOptionalPlaceholders( - for wrappedType: BridgeType, - scope: JSGlueVariableScope, - printer: CodeFragmentPrinter - ) -> Bool { - let params = wrappedType.wasmParams - if params.isEmpty { - return false - } - for param in params { - emitPush(for: param.type, value: param.type.jsZeroLiteral, scope: scope, printer: printer) - } - return true - } - + /// Lower an optional value to the stack using the **conditional** protocol: + /// push isSome flag, then conditionally push the payload (no placeholders for nil). private static func stackOptionalLower( wrappedType: BridgeType, kind: JSOptionalKind, @@ -1244,23 +1230,7 @@ struct IntrinsicJSFragment: Sendable { for line in ifBodyPrinter.lines { printer.write(line) } - let placeholderPrinter = CodeFragmentPrinter() - let hasPlaceholders = emitOptionalPlaceholders( - for: wrappedType, - scope: scope, - printer: placeholderPrinter - ) - if hasPlaceholders { - printer.write("} else {") - printer.indent { - for line in placeholderPrinter.lines { - printer.write(line) - } - } - printer.write("}") - } else { - printer.write("}") - } + printer.write("}") scope.emitPushI32Parameter("\(isSomeVar) ? 1 : 0", printer: printer) return [] } @@ -1744,109 +1714,21 @@ struct IntrinsicJSFragment: Sendable { private static func associatedValuePushPayload(type: BridgeType) throws -> IntrinsicJSFragment { switch type { case .nullable(let wrappedType, let kind): - return try associatedValueOptionalPushPayload(wrappedType: wrappedType, kind: kind) + return try optionalElementLowerFragment(wrappedType: wrappedType, kind: kind) default: return try stackLowerFragment(elementType: type) } } - private static func associatedValueOptionalPushPayload( - wrappedType: BridgeType, - kind: JSOptionalKind - ) throws -> IntrinsicJSFragment { - if wrappedType.isSingleParamScalar { - let wasmType = wrappedType.wasmParams[0].type - let stackCoerce = wrappedType.stackLowerCoerce - return IntrinsicJSFragment( - parameters: ["value"], - printCode: { arguments, context in - let (scope, printer) = (context.scope, context.printer) - let value = arguments[0] - let isSomeVar = scope.variable("isSome") - printer.write("const \(isSomeVar) = \(kind.presenceCheck(value: value));") - var coerced: String - if let coerce = stackCoerce { - coerced = coerce.replacingOccurrences(of: "$0", with: value) - if coerced.contains("?") && !coerced.hasPrefix("(") { - coerced = "(\(coerced))" - } - } else { - coerced = value - } - emitPush( - for: wasmType, - value: "\(isSomeVar) ? \(coerced) : \(wasmType.jsZeroLiteral)", - scope: scope, - printer: printer - ) - scope.emitPushI32Parameter("\(isSomeVar) ? 1 : 0", printer: printer) - return [] - } - ) - } - - let innerFragment = try stackLowerFragment(elementType: wrappedType) - return stackOptionalLower( - wrappedType: wrappedType, - kind: kind, - innerFragment: innerFragment - ) - } - private static func associatedValuePopPayload(type: BridgeType) throws -> IntrinsicJSFragment { switch type { case .nullable(let wrappedType, let kind): - return associatedValueOptionalPopPayload(wrappedType: wrappedType, kind: kind) + return try optionalElementRaiseFragment(wrappedType: wrappedType, kind: kind) default: return try stackLiftFragment(elementType: type) } } - private static func associatedValueOptionalPopPayload( - wrappedType: BridgeType, - kind: JSOptionalKind - ) -> IntrinsicJSFragment { - return IntrinsicJSFragment( - parameters: [], - printCode: { arguments, context in - let (scope, printer) = (context.scope, context.printer) - let optVar = scope.variable("optional") - let isSomeVar = scope.variable("isSome") - - printer.write("const \(isSomeVar) = \(scope.popI32());") - printer.write("let \(optVar);") - printer.write("if (\(isSomeVar)) {") - try printer.indent { - // For optional associated value enums, Swift uses bridgeJSLowerParameter() - // which pushes caseId to i32Stack (same as bridgeJSLowerReturn()). - if case .associatedValueEnum(let fullName) = wrappedType { - let base = fullName.components(separatedBy: ".").last ?? fullName - let caseIdVar = scope.variable("caseId") - printer.write("const \(caseIdVar) = \(scope.popI32());") - printer.write( - "\(optVar) = \(JSGlueVariableScope.reservedEnumHelpers).\(base).lift(\(caseIdVar));" - ) - } else { - let wrappedFragment = try associatedValuePopPayload(type: wrappedType) - let wrappedResults = try wrappedFragment.printCode([], context) - if let wrappedResult = wrappedResults.first { - printer.write("\(optVar) = \(wrappedResult);") - } else { - printer.write("\(optVar) = undefined;") - } - } - } - printer.write("} else {") - printer.indent { - printer.write("\(optVar) = \(kind.absenceLiteral);") - } - printer.write("}") - - return [optVar] - } - ) - } - private static func swiftStructLower(structBase: String) -> IntrinsicJSFragment { IntrinsicJSFragment( parameters: ["value"], @@ -2252,6 +2134,35 @@ struct IntrinsicJSFragment: Sendable { wrappedType: BridgeType, kind: JSOptionalKind ) throws -> IntrinsicJSFragment { + if case .associatedValueEnum(let fullName) = wrappedType { + let base = fullName.components(separatedBy: ".").last ?? fullName + let absenceLiteral = kind.absenceLiteral + return IntrinsicJSFragment( + parameters: [], + printCode: { arguments, context in + let (scope, printer) = (context.scope, context.printer) + let caseIdVar = scope.variable("caseId") + let resultVar = scope.variable("optValue") + + printer.write("const \(caseIdVar) = \(scope.popI32());") + printer.write("let \(resultVar);") + printer.write("if (\(caseIdVar) === -1) {") + printer.indent { + printer.write("\(resultVar) = \(absenceLiteral);") + } + printer.write("} else {") + printer.indent { + printer.write( + "\(resultVar) = \(JSGlueVariableScope.reservedEnumHelpers).\(base).lift(\(caseIdVar));" + ) + } + printer.write("}") + + return [resultVar] + } + ) + } + let absenceLiteral = kind.absenceLiteral return IntrinsicJSFragment( parameters: [], @@ -2283,10 +2194,42 @@ struct IntrinsicJSFragment: Sendable { ) } + /// Lower an optional element to the stack using the **conditional** protocol: + /// push isSome flag, then conditionally push the payload (no placeholders for nil). private static func optionalElementLowerFragment( wrappedType: BridgeType, kind: JSOptionalKind ) throws -> IntrinsicJSFragment { + if case .associatedValueEnum(let fullName) = wrappedType { + let base = fullName.components(separatedBy: ".").last ?? fullName + return IntrinsicJSFragment( + parameters: ["value"], + printCode: { arguments, context in + let (scope, printer) = (context.scope, context.printer) + let value = arguments[0] + let isSomeVar = scope.variable("isSome") + let presenceExpr = kind.presenceCheck(value: value) + + printer.write("const \(isSomeVar) = \(presenceExpr) ? 1 : 0;") + printer.write("if (\(isSomeVar)) {") + printer.indent { + let caseIdVar = scope.variable("caseId") + printer.write( + "const \(caseIdVar) = \(JSGlueVariableScope.reservedEnumHelpers).\(base).lower(\(value));" + ) + scope.emitPushI32Parameter(caseIdVar, printer: printer) + } + printer.write("} else {") + printer.indent { + scope.emitPushI32Parameter("-1", printer: printer) + } + printer.write("}") + + return [] + } + ) + } + return IntrinsicJSFragment( parameters: ["value"], printCode: { arguments, context in @@ -2304,23 +2247,7 @@ struct IntrinsicJSFragment: Sendable { context ) } - let placeholderPrinter = CodeFragmentPrinter() - let hasPlaceholders = emitOptionalPlaceholders( - for: wrappedType, - scope: scope, - printer: placeholderPrinter - ) - if hasPlaceholders { - printer.write("} else {") - printer.indent { - for line in placeholderPrinter.lines { - printer.write(line) - } - } - printer.write("}") - } else { - printer.write("}") - } + printer.write("}") scope.emitPushI32Parameter(isSomeVar, printer: printer) return [] @@ -2506,47 +2433,7 @@ struct IntrinsicJSFragment: Sendable { } ) case .nullable(let wrappedType, let kind): - if wrappedType.isSingleParamScalar { - let wasmType = wrappedType.wasmParams[0].type - let stackCoerce = wrappedType.stackLowerCoerce - return IntrinsicJSFragment( - parameters: ["value"], - printCode: { arguments, context in - let (scope, printer) = (context.scope, context.printer) - let value = arguments[0] - let isSomeVar = scope.variable("isSome") - printer.write("const \(isSomeVar) = \(kind.presenceCheck(value: value));") - let coerced: String - if let coerce = stackCoerce { - coerced = coerce.replacingOccurrences(of: "$0", with: value) - } else { - coerced = value - } - printer.write("if (\(isSomeVar)) {") - printer.indent { - emitPush(for: wasmType, value: coerced, scope: scope, printer: printer) - } - printer.write("} else {") - printer.indent { - emitPush(for: wasmType, value: wasmType.jsZeroLiteral, scope: scope, printer: printer) - } - printer.write("}") - scope.emitPushI32Parameter("\(isSomeVar) ? 1 : 0", printer: printer) - return [] - } - ) - } - - let innerFragment = try structFieldLowerFragment( - type: wrappedType, - fieldName: fieldName, - allStructs: allStructs - ) - return stackOptionalLower( - wrappedType: wrappedType, - kind: kind, - innerFragment: innerFragment - ) + return try optionalElementLowerFragment(wrappedType: wrappedType, kind: kind) case .swiftStruct(let nestedName): return IntrinsicJSFragment( parameters: ["value"], @@ -2584,50 +2471,7 @@ struct IntrinsicJSFragment: Sendable { case .jsValue: preconditionFailure("Struct field of JSValue is not supported yet") case .nullable(let wrappedType, let kind): - return IntrinsicJSFragment( - parameters: [], - printCode: { arguments, context in - let (scope, printer) = (context.scope, context.printer) - let isSomeVar = scope.variable("isSome") - let optVar = scope.variable("optional") - printer.write("const \(isSomeVar) = \(scope.popI32());") - printer.write("let \(optVar);") - printer.write("if (\(isSomeVar)) {") - try printer.indent { - // Special handling for associated value enum - in struct fields, case ID is pushed to i32Stack - if case .associatedValueEnum(let enumName) = wrappedType { - let base = enumName.components(separatedBy: ".").last ?? enumName - let caseIdVar = scope.variable("enumCaseId") - printer.write("const \(caseIdVar) = \(scope.popI32());") - printer.write( - "\(optVar) = \(JSGlueVariableScope.reservedEnumHelpers).\(base).lift(\(caseIdVar));" - ) - } else { - let wrappedFragment = try structFieldLiftFragment( - field: ExportedProperty( - name: field.name, - type: wrappedType, - isReadonly: true, - isStatic: false - ), - allStructs: allStructs - ) - let wrappedResults = try wrappedFragment.printCode([], context) - if let wrappedResult = wrappedResults.first { - printer.write("\(optVar) = \(wrappedResult);") - } else { - printer.write("\(optVar) = undefined;") - } - } - } - printer.write("} else {") - printer.indent { - printer.write("\(optVar) = \(kind.absenceLiteral);") - } - printer.write("}") - return [optVar] - } - ) + return try optionalElementRaiseFragment(wrappedType: wrappedType, kind: kind) case .swiftStruct(let nestedName): return IntrinsicJSFragment( parameters: [], diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.swift index 6b6b59fce..6ced24393 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.swift @@ -239,11 +239,7 @@ public func _bjs_processOptionalIntArray() -> Void { return __result }()) for __bjs_elem_ret in ret { - let __bjs_isSome_ret_elem = __bjs_elem_ret != nil - if let __bjs_unwrapped_ret_elem = __bjs_elem_ret { - __bjs_unwrapped_ret_elem.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_ret_elem ? 1 : 0) + __bjs_elem_ret.bridgeJSStackPush() } _swift_js_push_i32(Int32(ret.count)) #else @@ -266,11 +262,7 @@ public func _bjs_processOptionalStringArray() -> Void { return __result }()) for __bjs_elem_ret in ret { - let __bjs_isSome_ret_elem = __bjs_elem_ret != nil - if let __bjs_unwrapped_ret_elem = __bjs_elem_ret { - __bjs_unwrapped_ret_elem.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_ret_elem ? 1 : 0) + __bjs_elem_ret.bridgeJSStackPush() } _swift_js_push_i32(Int32(ret.count)) #else @@ -327,11 +319,7 @@ public func _bjs_processOptionalDirectionArray() -> Void { return __result }()) for __bjs_elem_ret in ret { - let __bjs_isSome_ret_elem = __bjs_elem_ret != nil - if let __bjs_unwrapped_ret_elem = __bjs_elem_ret { - __bjs_unwrapped_ret_elem.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_ret_elem ? 1 : 0) + __bjs_elem_ret.bridgeJSStackPush() } _swift_js_push_i32(Int32(ret.count)) #else @@ -354,11 +342,7 @@ public func _bjs_processOptionalStatusArray() -> Void { return __result }()) for __bjs_elem_ret in ret { - let __bjs_isSome_ret_elem = __bjs_elem_ret != nil - if let __bjs_unwrapped_ret_elem = __bjs_elem_ret { - __bjs_unwrapped_ret_elem.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_ret_elem ? 1 : 0) + __bjs_elem_ret.bridgeJSStackPush() } _swift_js_push_i32(Int32(ret.count)) #else @@ -447,11 +431,7 @@ public func _bjs_processOptionalJSObjectArray() -> Void { return __result }()) for __bjs_elem_ret in ret { - let __bjs_isSome_ret_elem = __bjs_elem_ret != nil - if let __bjs_unwrapped_ret_elem = __bjs_elem_ret { - __bjs_unwrapped_ret_elem.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_ret_elem ? 1 : 0) + __bjs_elem_ret.bridgeJSStackPush() } _swift_js_push_i32(Int32(ret.count)) #else diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValue.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValue.swift index 838c55122..fc3a18453 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValue.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValue.swift @@ -171,40 +171,16 @@ extension APIOptionalResult: _BridgedSwiftAssociatedValueEnum { @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPushPayload() -> Int32 { switch self { case .success(let param0): - let __bjs_isSome_param0 = param0 != nil - if let __bjs_unwrapped_param0 = param0 { - __bjs_unwrapped_param0.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_param0 ? 1 : 0) + param0.bridgeJSStackPush() return Int32(0) case .failure(let param0, let param1): - let __bjs_isSome_param0 = param0 != nil - if let __bjs_unwrapped_param0 = param0 { - __bjs_unwrapped_param0.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_param0 ? 1 : 0) - let __bjs_isSome_param1 = param1 != nil - if let __bjs_unwrapped_param1 = param1 { - __bjs_unwrapped_param1.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_param1 ? 1 : 0) + param0.bridgeJSStackPush() + param1.bridgeJSStackPush() return Int32(1) case .status(let param0, let param1, let param2): - let __bjs_isSome_param0 = param0 != nil - if let __bjs_unwrapped_param0 = param0 { - __bjs_unwrapped_param0.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_param0 ? 1 : 0) - let __bjs_isSome_param1 = param1 != nil - if let __bjs_unwrapped_param1 = param1 { - __bjs_unwrapped_param1.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_param1 ? 1 : 0) - let __bjs_isSome_param2 = param2 != nil - if let __bjs_unwrapped_param2 = param2 { - __bjs_unwrapped_param2.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_param2 ? 1 : 0) + param0.bridgeJSStackPush() + param1.bridgeJSStackPush() + param2.bridgeJSStackPush() return Int32(2) } } @@ -283,18 +259,10 @@ extension TypedPayloadResult: _BridgedSwiftAssociatedValueEnum { param0.bridgeJSStackPush() return Int32(1) case .optPrecision(let param0): - let __bjs_isSome_param0 = param0 != nil - if let __bjs_unwrapped_param0 = param0 { - __bjs_unwrapped_param0.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_param0 ? 1 : 0) + param0.bridgeJSStackPush() return Int32(2) case .optDirection(let param0): - let __bjs_isSome_param0 = param0 != nil - if let __bjs_unwrapped_param0 = param0 { - __bjs_unwrapped_param0.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_param0 ? 1 : 0) + param0.bridgeJSStackPush() return Int32(3) case .empty: return Int32(4) @@ -371,25 +339,13 @@ extension OptionalAllTypesResult: _BridgedSwiftAssociatedValueEnum { param0.bridgeJSStackPush() return Int32(0) case .optClass(let param0): - let __bjs_isSome_param0 = param0 != nil - if let __bjs_unwrapped_param0 = param0 { - __bjs_unwrapped_param0.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_param0 ? 1 : 0) + param0.bridgeJSStackPush() return Int32(1) case .optJSObject(let param0): - let __bjs_isSome_param0 = param0 != nil - if let __bjs_unwrapped_param0 = param0 { - __bjs_unwrapped_param0.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_param0 ? 1 : 0) + param0.bridgeJSStackPush() return Int32(2) case .optNestedEnum(let param0): - let __bjs_isSome_param0 = param0 != nil - if let __bjs_unwrapped_param0 = param0 { - __bjs_unwrapped_param0.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_param0 ? 1 : 0) + param0.bridgeJSStackPush() return Int32(3) case .optArray(let param0): param0.bridgeJSStackPush() diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportedTypeInExportedInterface.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportedTypeInExportedInterface.swift index c72cda7ed..809dfb43a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportedTypeInExportedInterface.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportedTypeInExportedInterface.swift @@ -7,11 +7,7 @@ extension FooContainer: _BridgedSwiftStruct { @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() { self.foo.jsObject.bridgeJSStackPush() - let __bjs_isSome_optionalFoo = self.optionalFoo != nil - if let __bjs_unwrapped_optionalFoo = self.optionalFoo { - __bjs_unwrapped_optionalFoo.jsObject.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_optionalFoo ? 1 : 0) + self.optionalFoo.bridgeJSStackPush() } init(unsafelyCopying jsObject: JSObject) { @@ -101,11 +97,7 @@ public func _bjs_processOptionalFooArray() -> Void { return __result }()) for __bjs_elem_ret in ret { - let __bjs_isSome_ret_elem = __bjs_elem_ret != nil - if let __bjs_unwrapped_ret_elem = __bjs_elem_ret { - __bjs_unwrapped_ret_elem.jsObject.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_ret_elem ? 1 : 0) + __bjs_elem_ret.bridgeJSStackPush() } _swift_js_push_i32(Int32(ret.count)) #else diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift index 2adffc113..6fccb3280 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift @@ -15,16 +15,8 @@ extension DataPoint: _BridgedSwiftStruct { self.x.bridgeJSStackPush() self.y.bridgeJSStackPush() self.label.bridgeJSStackPush() - let __bjs_isSome_optCount = self.optCount != nil - if let __bjs_unwrapped_optCount = self.optCount { - __bjs_unwrapped_optCount.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_optCount ? 1 : 0) - let __bjs_isSome_optFlag = self.optFlag != nil - if let __bjs_unwrapped_optFlag = self.optFlag { - __bjs_unwrapped_optFlag.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_optFlag ? 1 : 0) + self.optCount.bridgeJSStackPush() + self.optFlag.bridgeJSStackPush() } init(unsafelyCopying jsObject: JSObject) { @@ -85,11 +77,7 @@ extension Address: _BridgedSwiftStruct { @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() { self.street.bridgeJSStackPush() self.city.bridgeJSStackPush() - let __bjs_isSome_zipCode = self.zipCode != nil - if let __bjs_unwrapped_zipCode = self.zipCode { - __bjs_unwrapped_zipCode.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_zipCode ? 1 : 0) + self.zipCode.bridgeJSStackPush() } init(unsafelyCopying jsObject: JSObject) { @@ -141,11 +129,7 @@ extension Person: _BridgedSwiftStruct { self.name.bridgeJSStackPush() self.age.bridgeJSStackPush() self.address.bridgeJSStackPush() - let __bjs_isSome_email = self.email != nil - if let __bjs_unwrapped_email = self.email { - __bjs_unwrapped_email.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_email ? 1 : 0) + self.email.bridgeJSStackPush() } init(unsafelyCopying jsObject: JSObject) { @@ -243,11 +227,7 @@ extension Measurement: _BridgedSwiftStruct { @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() { self.value.bridgeJSStackPush() self.precision.bridgeJSStackPush() - let __bjs_isSome_optionalPrecision = self.optionalPrecision != nil - if let __bjs_unwrapped_optionalPrecision = self.optionalPrecision { - __bjs_unwrapped_optionalPrecision.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_optionalPrecision ? 1 : 0) + self.optionalPrecision.bridgeJSStackPush() } init(unsafelyCopying jsObject: JSObject) { @@ -414,11 +394,7 @@ extension Container: _BridgedSwiftStruct { @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() { self.object.bridgeJSStackPush() - let __bjs_isSome_optionalObject = self.optionalObject != nil - if let __bjs_unwrapped_optionalObject = self.optionalObject { - __bjs_unwrapped_optionalObject.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_optionalObject ? 1 : 0) + self.optionalObject.bridgeJSStackPush() } init(unsafelyCopying jsObject: JSObject) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js index d0665da73..81b432012 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js @@ -598,8 +598,6 @@ export async function createInstantiator(options, swift) { const isSome = elem != null ? 1 : 0; if (isSome) { i32Stack.push((elem | 0)); - } else { - i32Stack.push(0); } i32Stack.push(isSome); } @@ -629,9 +627,6 @@ export async function createInstantiator(options, swift) { const id = swift.memory.retain(bytes); i32Stack.push(bytes.length); i32Stack.push(id); - } else { - i32Stack.push(0); - i32Stack.push(0); } i32Stack.push(isSome); } @@ -710,8 +705,6 @@ export async function createInstantiator(options, swift) { const isSome = elem != null ? 1 : 0; if (isSome) { i32Stack.push((elem | 0)); - } else { - i32Stack.push(0); } i32Stack.push(isSome); } @@ -738,8 +731,6 @@ export async function createInstantiator(options, swift) { const isSome = elem != null ? 1 : 0; if (isSome) { i32Stack.push((elem | 0)); - } else { - i32Stack.push(0); } i32Stack.push(isSome); } @@ -901,8 +892,6 @@ export async function createInstantiator(options, swift) { if (isSome) { const objId = swift.memory.retain(elem); i32Stack.push(objId); - } else { - i32Stack.push(0); } i32Stack.push(isSome); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js index 268caf407..8627b2c80 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js @@ -386,8 +386,6 @@ export async function createInstantiator(options, swift) { const isSome = value != null ? 1 : 0; if (isSome) { ptrStack.push(value.pointer); - } else { - ptrStack.push(0); } i32Stack.push(isSome); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js index 55967a6a3..8e9dfa65f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js @@ -379,46 +379,48 @@ export async function createInstantiator(options, swift) { const enumTag = value.tag; switch (enumTag) { case APIOptionalResultValues.Tag.Success: { - const isSome = value.param0 != null; + const isSome = value.param0 != null ? 1 : 0; if (isSome) { const bytes = textEncoder.encode(value.param0); const id = swift.memory.retain(bytes); i32Stack.push(bytes.length); i32Stack.push(id); - } else { - i32Stack.push(0); - i32Stack.push(0); } - i32Stack.push(isSome ? 1 : 0); + i32Stack.push(isSome); return APIOptionalResultValues.Tag.Success; } case APIOptionalResultValues.Tag.Failure: { - const isSome = value.param1 != null; - i32Stack.push(isSome ? (value.param1 ? 1 : 0) : 0); - i32Stack.push(isSome ? 1 : 0); - const isSome1 = value.param0 != null; - i32Stack.push(isSome1 ? (value.param0 | 0) : 0); - i32Stack.push(isSome1 ? 1 : 0); + const isSome = value.param1 != null ? 1 : 0; + if (isSome) { + i32Stack.push(value.param1 ? 1 : 0); + } + i32Stack.push(isSome); + const isSome1 = value.param0 != null ? 1 : 0; + if (isSome1) { + i32Stack.push((value.param0 | 0)); + } + i32Stack.push(isSome1); return APIOptionalResultValues.Tag.Failure; } case APIOptionalResultValues.Tag.Status: { - const isSome = value.param2 != null; + const isSome = value.param2 != null ? 1 : 0; if (isSome) { const bytes = textEncoder.encode(value.param2); const id = swift.memory.retain(bytes); i32Stack.push(bytes.length); i32Stack.push(id); - } else { - i32Stack.push(0); - i32Stack.push(0); } - i32Stack.push(isSome ? 1 : 0); - const isSome1 = value.param1 != null; - i32Stack.push(isSome1 ? (value.param1 | 0) : 0); - i32Stack.push(isSome1 ? 1 : 0); - const isSome2 = value.param0 != null; - i32Stack.push(isSome2 ? (value.param0 ? 1 : 0) : 0); - i32Stack.push(isSome2 ? 1 : 0); + i32Stack.push(isSome); + const isSome1 = value.param1 != null ? 1 : 0; + if (isSome1) { + i32Stack.push((value.param1 | 0)); + } + i32Stack.push(isSome1); + const isSome2 = value.param0 != null ? 1 : 0; + if (isSome2) { + i32Stack.push(value.param0 ? 1 : 0); + } + i32Stack.push(isSome2); return APIOptionalResultValues.Tag.Status; } default: throw new Error("Unknown APIOptionalResultValues tag: " + String(enumTag)); @@ -429,60 +431,60 @@ export async function createInstantiator(options, swift) { switch (tag) { case APIOptionalResultValues.Tag.Success: { const isSome = i32Stack.pop(); - let optional; - if (isSome) { - const string = strStack.pop(); - optional = string; + let optValue; + if (isSome === 0) { + optValue = null; } else { - optional = null; + const string = strStack.pop(); + optValue = string; } - return { tag: APIOptionalResultValues.Tag.Success, param0: optional }; + return { tag: APIOptionalResultValues.Tag.Success, param0: optValue }; } case APIOptionalResultValues.Tag.Failure: { const isSome = i32Stack.pop(); - let optional; - if (isSome) { - const bool = i32Stack.pop() !== 0; - optional = bool; + let optValue; + if (isSome === 0) { + optValue = null; } else { - optional = null; + const bool = i32Stack.pop() !== 0; + optValue = bool; } const isSome1 = i32Stack.pop(); - let optional1; - if (isSome1) { - const int = i32Stack.pop(); - optional1 = int; + let optValue1; + if (isSome1 === 0) { + optValue1 = null; } else { - optional1 = null; + const int = i32Stack.pop(); + optValue1 = int; } - return { tag: APIOptionalResultValues.Tag.Failure, param0: optional1, param1: optional }; + return { tag: APIOptionalResultValues.Tag.Failure, param0: optValue1, param1: optValue }; } case APIOptionalResultValues.Tag.Status: { const isSome = i32Stack.pop(); - let optional; - if (isSome) { - const string = strStack.pop(); - optional = string; + let optValue; + if (isSome === 0) { + optValue = null; } else { - optional = null; + const string = strStack.pop(); + optValue = string; } const isSome1 = i32Stack.pop(); - let optional1; - if (isSome1) { - const int = i32Stack.pop(); - optional1 = int; + let optValue1; + if (isSome1 === 0) { + optValue1 = null; } else { - optional1 = null; + const int = i32Stack.pop(); + optValue1 = int; } const isSome2 = i32Stack.pop(); - let optional2; - if (isSome2) { - const bool = i32Stack.pop() !== 0; - optional2 = bool; + let optValue2; + if (isSome2 === 0) { + optValue2 = null; } else { - optional2 = null; + const bool = i32Stack.pop() !== 0; + optValue2 = bool; } - return { tag: APIOptionalResultValues.Tag.Status, param0: optional2, param1: optional1, param2: optional }; + return { tag: APIOptionalResultValues.Tag.Status, param0: optValue2, param1: optValue1, param2: optValue }; } default: throw new Error("Unknown APIOptionalResultValues tag returned from Swift: " + String(tag)); } @@ -501,15 +503,19 @@ export async function createInstantiator(options, swift) { return TypedPayloadResultValues.Tag.Direction; } case TypedPayloadResultValues.Tag.OptPrecision: { - const isSome = value.param0 != null; - f32Stack.push(isSome ? Math.fround(value.param0) : 0.0); - i32Stack.push(isSome ? 1 : 0); + const isSome = value.param0 != null ? 1 : 0; + if (isSome) { + f32Stack.push(Math.fround(value.param0)); + } + i32Stack.push(isSome); return TypedPayloadResultValues.Tag.OptPrecision; } case TypedPayloadResultValues.Tag.OptDirection: { - const isSome = value.param0 != null; - i32Stack.push(isSome ? (value.param0 | 0) : 0); - i32Stack.push(isSome ? 1 : 0); + const isSome = value.param0 != null ? 1 : 0; + if (isSome) { + i32Stack.push((value.param0 | 0)); + } + i32Stack.push(isSome); return TypedPayloadResultValues.Tag.OptDirection; } case TypedPayloadResultValues.Tag.Empty: { @@ -531,25 +537,25 @@ export async function createInstantiator(options, swift) { } case TypedPayloadResultValues.Tag.OptPrecision: { const isSome = i32Stack.pop(); - let optional; - if (isSome) { - const rawValue = f32Stack.pop(); - optional = rawValue; + let optValue; + if (isSome === 0) { + optValue = null; } else { - optional = null; + const rawValue = f32Stack.pop(); + optValue = rawValue; } - return { tag: TypedPayloadResultValues.Tag.OptPrecision, param0: optional }; + return { tag: TypedPayloadResultValues.Tag.OptPrecision, param0: optValue }; } case TypedPayloadResultValues.Tag.OptDirection: { const isSome = i32Stack.pop(); - let optional; - if (isSome) { - const caseId = i32Stack.pop(); - optional = caseId; + let optValue; + if (isSome === 0) { + optValue = null; } else { - optional = null; + const caseId = i32Stack.pop(); + optValue = caseId; } - return { tag: TypedPayloadResultValues.Tag.OptDirection, param0: optional }; + return { tag: TypedPayloadResultValues.Tag.OptDirection, param0: optValue }; } case TypedPayloadResultValues.Tag.Empty: return { tag: TypedPayloadResultValues.Tag.Empty }; default: throw new Error("Unknown TypedPayloadResultValues tag returned from Swift: " + String(tag)); @@ -633,54 +639,49 @@ export async function createInstantiator(options, swift) { const enumTag = value.tag; switch (enumTag) { case OptionalAllTypesResultValues.Tag.OptStruct: { - const isSome = value.param0 != null; + const isSome = value.param0 != null ? 1 : 0; if (isSome) { structHelpers.Point.lower(value.param0); } - i32Stack.push(isSome ? 1 : 0); + i32Stack.push(isSome); return OptionalAllTypesResultValues.Tag.OptStruct; } case OptionalAllTypesResultValues.Tag.OptClass: { - const isSome = value.param0 != null; + const isSome = value.param0 != null ? 1 : 0; if (isSome) { ptrStack.push(value.param0.pointer); - } else { - ptrStack.push(0); } - i32Stack.push(isSome ? 1 : 0); + i32Stack.push(isSome); return OptionalAllTypesResultValues.Tag.OptClass; } case OptionalAllTypesResultValues.Tag.OptJSObject: { - const isSome = value.param0 != null; + const isSome = value.param0 != null ? 1 : 0; if (isSome) { const objId = swift.memory.retain(value.param0); i32Stack.push(objId); - } else { - i32Stack.push(0); } - i32Stack.push(isSome ? 1 : 0); + i32Stack.push(isSome); return OptionalAllTypesResultValues.Tag.OptJSObject; } case OptionalAllTypesResultValues.Tag.OptNestedEnum: { - const isSome = value.param0 != null; + const isSome = value.param0 != null ? 1 : 0; if (isSome) { const caseId = enumHelpers.APIResult.lower(value.param0); i32Stack.push(caseId); } else { - i32Stack.push(0); + i32Stack.push(-1); } - i32Stack.push(isSome ? 1 : 0); return OptionalAllTypesResultValues.Tag.OptNestedEnum; } case OptionalAllTypesResultValues.Tag.OptArray: { - const isSome = value.param0 != null; + const isSome = value.param0 != null ? 1 : 0; if (isSome) { for (const elem of value.param0) { i32Stack.push((elem | 0)); } i32Stack.push(value.param0.length); } - i32Stack.push(isSome ? 1 : 0); + i32Stack.push(isSome); return OptionalAllTypesResultValues.Tag.OptArray; } case OptionalAllTypesResultValues.Tag.Empty: { @@ -694,55 +695,56 @@ export async function createInstantiator(options, swift) { switch (tag) { case OptionalAllTypesResultValues.Tag.OptStruct: { const isSome = i32Stack.pop(); - let optional; - if (isSome) { - const struct = structHelpers.Point.lift(); - optional = struct; + let optValue; + if (isSome === 0) { + optValue = null; } else { - optional = null; + const struct = structHelpers.Point.lift(); + optValue = struct; } - return { tag: OptionalAllTypesResultValues.Tag.OptStruct, param0: optional }; + return { tag: OptionalAllTypesResultValues.Tag.OptStruct, param0: optValue }; } case OptionalAllTypesResultValues.Tag.OptClass: { const isSome = i32Stack.pop(); - let optional; - if (isSome) { + let optValue; + if (isSome === 0) { + optValue = null; + } else { const ptr = ptrStack.pop(); const obj = _exports['User'].__construct(ptr); - optional = obj; - } else { - optional = null; + optValue = obj; } - return { tag: OptionalAllTypesResultValues.Tag.OptClass, param0: optional }; + return { tag: OptionalAllTypesResultValues.Tag.OptClass, param0: optValue }; } case OptionalAllTypesResultValues.Tag.OptJSObject: { const isSome = i32Stack.pop(); - let optional; - if (isSome) { + let optValue; + if (isSome === 0) { + optValue = null; + } else { const objId = i32Stack.pop(); const obj = swift.memory.getObject(objId); swift.memory.release(objId); - optional = obj; - } else { - optional = null; + optValue = obj; } - return { tag: OptionalAllTypesResultValues.Tag.OptJSObject, param0: optional }; + return { tag: OptionalAllTypesResultValues.Tag.OptJSObject, param0: optValue }; } case OptionalAllTypesResultValues.Tag.OptNestedEnum: { - const isSome = i32Stack.pop(); - let optional; - if (isSome) { - const caseId = i32Stack.pop(); - optional = enumHelpers.APIResult.lift(caseId); + const caseId = i32Stack.pop(); + let optValue; + if (caseId === -1) { + optValue = null; } else { - optional = null; + optValue = enumHelpers.APIResult.lift(caseId); } - return { tag: OptionalAllTypesResultValues.Tag.OptNestedEnum, param0: optional }; + return { tag: OptionalAllTypesResultValues.Tag.OptNestedEnum, param0: optValue }; } case OptionalAllTypesResultValues.Tag.OptArray: { const isSome = i32Stack.pop(); - let optional; - if (isSome) { + let optValue; + if (isSome === 0) { + optValue = null; + } else { const arrayLen = i32Stack.pop(); const arrayResult = []; for (let i = 0; i < arrayLen; i++) { @@ -750,11 +752,9 @@ export async function createInstantiator(options, swift) { arrayResult.push(int); } arrayResult.reverse(); - optional = arrayResult; - } else { - optional = null; + optValue = arrayResult; } - return { tag: OptionalAllTypesResultValues.Tag.OptArray, param0: optional }; + return { tag: OptionalAllTypesResultValues.Tag.OptArray, param0: optValue }; } case OptionalAllTypesResultValues.Tag.Empty: return { tag: OptionalAllTypesResultValues.Tag.Empty }; default: throw new Error("Unknown OptionalAllTypesResultValues tag returned from Swift: " + String(tag)); diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js index c0c9704ef..8b938f75a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js @@ -37,45 +37,33 @@ export async function createInstantiator(options, swift) { id = undefined; } i32Stack.push(id !== undefined ? id : 0); - const isSome = value.optionalFoo != null; + const isSome = value.optionalFoo != null ? 1 : 0; if (isSome) { - let id1; - if (value.optionalFoo != null) { - id1 = swift.memory.retain(value.optionalFoo); - } else { - id1 = undefined; - } - i32Stack.push(id1 !== undefined ? id1 : 0); - } else { - i32Stack.push(0); + const objId = swift.memory.retain(value.optionalFoo); + i32Stack.push(objId); } - i32Stack.push(isSome ? 1 : 0); + i32Stack.push(isSome); }, lift: () => { const isSome = i32Stack.pop(); - let optional; - if (isSome) { - const objectId = i32Stack.pop(); - let value; - if (objectId !== 0) { - value = swift.memory.getObject(objectId); - swift.memory.release(objectId); - } else { - value = null; - } - optional = value; + let optValue; + if (isSome === 0) { + optValue = null; } else { - optional = null; - } - const objectId1 = i32Stack.pop(); - let value1; - if (objectId1 !== 0) { - value1 = swift.memory.getObject(objectId1); - swift.memory.release(objectId1); + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + optValue = obj; + } + const objectId = i32Stack.pop(); + let value; + if (objectId !== 0) { + value = swift.memory.getObject(objectId); + swift.memory.release(objectId); } else { - value1 = null; + value = null; } - return { foo: value1, optionalFoo: optional }; + return { foo: value, optionalFoo: optValue }; } }); @@ -303,8 +291,6 @@ export async function createInstantiator(options, swift) { if (isSome) { const objId = swift.memory.retain(elem); i32Stack.push(objId); - } else { - i32Stack.push(0); } i32Stack.push(isSome); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js index cc973e379..617bda36b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js @@ -41,42 +41,38 @@ export async function createInstantiator(options, swift) { const id = swift.memory.retain(bytes); i32Stack.push(bytes.length); i32Stack.push(id); - const isSome = value.optCount != null; + const isSome = value.optCount != null ? 1 : 0; if (isSome) { i32Stack.push((value.optCount | 0)); - } else { - i32Stack.push(0); } - i32Stack.push(isSome ? 1 : 0); - const isSome1 = value.optFlag != null; + i32Stack.push(isSome); + const isSome1 = value.optFlag != null ? 1 : 0; if (isSome1) { i32Stack.push(value.optFlag ? 1 : 0); - } else { - i32Stack.push(0); } - i32Stack.push(isSome1 ? 1 : 0); + i32Stack.push(isSome1); }, lift: () => { const isSome = i32Stack.pop(); - let optional; - if (isSome) { - const bool = i32Stack.pop() !== 0; - optional = bool; + let optValue; + if (isSome === 0) { + optValue = null; } else { - optional = null; + const bool = i32Stack.pop() !== 0; + optValue = bool; } const isSome1 = i32Stack.pop(); - let optional1; - if (isSome1) { - const int = i32Stack.pop(); - optional1 = int; + let optValue1; + if (isSome1 === 0) { + optValue1 = null; } else { - optional1 = null; + const int = i32Stack.pop(); + optValue1 = int; } const string = strStack.pop(); const f64 = f64Stack.pop(); const f641 = f64Stack.pop(); - return { x: f641, y: f64, label: string, optCount: optional1, optFlag: optional }; + return { x: f641, y: f64, label: string, optCount: optValue1, optFlag: optValue }; } }); const __bjs_createAddressHelpers = () => ({ @@ -89,26 +85,24 @@ export async function createInstantiator(options, swift) { const id1 = swift.memory.retain(bytes1); i32Stack.push(bytes1.length); i32Stack.push(id1); - const isSome = value.zipCode != null; + const isSome = value.zipCode != null ? 1 : 0; if (isSome) { i32Stack.push((value.zipCode | 0)); - } else { - i32Stack.push(0); } - i32Stack.push(isSome ? 1 : 0); + i32Stack.push(isSome); }, lift: () => { const isSome = i32Stack.pop(); - let optional; - if (isSome) { - const int = i32Stack.pop(); - optional = int; + let optValue; + if (isSome === 0) { + optValue = null; } else { - optional = null; + const int = i32Stack.pop(); + optValue = int; } const string = strStack.pop(); const string1 = strStack.pop(); - return { street: string1, city: string, zipCode: optional }; + return { street: string1, city: string, zipCode: optValue }; } }); const __bjs_createPersonHelpers = () => ({ @@ -119,31 +113,28 @@ export async function createInstantiator(options, swift) { i32Stack.push(id); i32Stack.push((value.age | 0)); structHelpers.Address.lower(value.address); - const isSome = value.email != null; + const isSome = value.email != null ? 1 : 0; if (isSome) { const bytes1 = textEncoder.encode(value.email); const id1 = swift.memory.retain(bytes1); i32Stack.push(bytes1.length); i32Stack.push(id1); - } else { - i32Stack.push(0); - i32Stack.push(0); } - i32Stack.push(isSome ? 1 : 0); + i32Stack.push(isSome); }, lift: () => { const isSome = i32Stack.pop(); - let optional; - if (isSome) { - const string = strStack.pop(); - optional = string; + let optValue; + if (isSome === 0) { + optValue = null; } else { - optional = null; + const string = strStack.pop(); + optValue = string; } const struct = structHelpers.Address.lift(); const int = i32Stack.pop(); const string1 = strStack.pop(); - return { name: string1, age: int, address: struct, email: optional }; + return { name: string1, age: int, address: struct, email: optValue }; } }); const __bjs_createSessionHelpers = () => ({ @@ -162,26 +153,24 @@ export async function createInstantiator(options, swift) { lower: (value) => { f64Stack.push(value.value); f32Stack.push(Math.fround(value.precision)); - const isSome = value.optionalPrecision != null; + const isSome = value.optionalPrecision != null ? 1 : 0; if (isSome) { f32Stack.push(Math.fround(value.optionalPrecision)); - } else { - f32Stack.push(0.0); } - i32Stack.push(isSome ? 1 : 0); + i32Stack.push(isSome); }, lift: () => { const isSome = i32Stack.pop(); - let optional; - if (isSome) { - const rawValue = f32Stack.pop(); - optional = rawValue; + let optValue; + if (isSome === 0) { + optValue = null; } else { - optional = null; + const rawValue = f32Stack.pop(); + optValue = rawValue; } const rawValue1 = f32Stack.pop(); const f64 = f64Stack.pop(); - return { value: f64, precision: rawValue1, optionalPrecision: optional }; + return { value: f64, precision: rawValue1, optionalPrecision: optValue }; } }); const __bjs_createConfigStructHelpers = () => ({ @@ -200,45 +189,33 @@ export async function createInstantiator(options, swift) { id = undefined; } i32Stack.push(id !== undefined ? id : 0); - const isSome = value.optionalObject != null; + const isSome = value.optionalObject != null ? 1 : 0; if (isSome) { - let id1; - if (value.optionalObject != null) { - id1 = swift.memory.retain(value.optionalObject); - } else { - id1 = undefined; - } - i32Stack.push(id1 !== undefined ? id1 : 0); - } else { - i32Stack.push(0); + const objId = swift.memory.retain(value.optionalObject); + i32Stack.push(objId); } - i32Stack.push(isSome ? 1 : 0); + i32Stack.push(isSome); }, lift: () => { const isSome = i32Stack.pop(); - let optional; - if (isSome) { - const objectId = i32Stack.pop(); - let value; - if (objectId !== 0) { - value = swift.memory.getObject(objectId); - swift.memory.release(objectId); - } else { - value = null; - } - optional = value; + let optValue; + if (isSome === 0) { + optValue = null; } else { - optional = null; - } - const objectId1 = i32Stack.pop(); - let value1; - if (objectId1 !== 0) { - value1 = swift.memory.getObject(objectId1); - swift.memory.release(objectId1); + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + optValue = obj; + } + const objectId = i32Stack.pop(); + let value; + if (objectId !== 0) { + value = swift.memory.getObject(objectId); + swift.memory.release(objectId); } else { - value1 = null; + value = null; } - return { object: value1, optionalObject: optional }; + return { object: value, optionalObject: optValue }; } }); diff --git a/Sources/JavaScriptKit/BridgeJSIntrinsics.swift b/Sources/JavaScriptKit/BridgeJSIntrinsics.swift index 5adccdc04..2f1e7feb0 100644 --- a/Sources/JavaScriptKit/BridgeJSIntrinsics.swift +++ b/Sources/JavaScriptKit/BridgeJSIntrinsics.swift @@ -146,6 +146,37 @@ public protocol _BridgedSwiftStackType { associatedtype StackLiftResult = Self static func bridgeJSStackPop() -> StackLiftResult consuming func bridgeJSStackPush() + + // MARK: Specialization points + + /// Specialization point for popping an `Optional` + static func bridgeJSStackPopAsOptional() -> StackLiftResult? + /// Specialization point for pushing an `Optional` + static func bridgeJSStackPushAsOptional(_ value: consuming Self?) +} + +extension _BridgedSwiftStackType { + /// Default implementation for popping an `Optional` using + /// a leading discriminator on the stack (0 for nil, 1 for some). + public static func bridgeJSStackPopAsOptional() -> StackLiftResult? { + let isSome = _swift_js_pop_i32() + if isSome == 0 { + return nil + } + return Self.bridgeJSStackPop() + } + + /// Default implementation for pushing an `Optional` using + /// a leading discriminator on the stack (0 for nil, 1 for some). + public static func bridgeJSStackPushAsOptional(_ value: consuming Self?) { + switch consume value { + case .none: + _swift_js_push_i32(0) + case .some(let value): + value.bridgeJSStackPush() + _swift_js_push_i32(1) + } + } } /// Types that bridge with the same (isSome, value) ABI as Optional. @@ -604,7 +635,8 @@ extension _BridgedSwiftCaseEnum { /// A protocol that Swift associated value enum types conform to. /// /// The conformance is automatically synthesized by the BridgeJS code generator. -public protocol _BridgedSwiftAssociatedValueEnum: _BridgedSwiftTypeLoweredIntoVoidType, _BridgedSwiftStackType { +public protocol _BridgedSwiftAssociatedValueEnum: _BridgedSwiftTypeLoweredIntoVoidType, _BridgedSwiftStackType +where StackLiftResult == Self { /// Pops the payload of the associated value enum from the stack. /// /// - Parameter caseId: The enum case ID. @@ -626,6 +658,23 @@ extension _BridgedSwiftAssociatedValueEnum { _swift_js_push_i32(bridgeJSStackPushPayload()) } + public static func bridgeJSStackPopAsOptional() -> Self? { + let discriminator = _swift_js_pop_i32() + if discriminator == -1 { + return nil + } + return bridgeJSStackPopPayload(discriminator) + } + + public static func bridgeJSStackPushAsOptional(_ value: consuming Self?) { + switch consume value { + case .none: + _swift_js_push_i32(-1) + case .some(let value): + _swift_js_push_i32(value.bridgeJSStackPushPayload()) + } + } + @_spi(BridgeJS) public static func bridgeJSLiftParameter(_ caseId: Int32) -> Self { return bridgeJSStackPopPayload(caseId) } @@ -646,7 +695,8 @@ extension _BridgedSwiftAssociatedValueEnum { /// A protocol that Swift struct types conform to. /// /// The conformance is automatically synthesized by the BridgeJS code generator. -public protocol _BridgedSwiftStruct: _BridgedSwiftTypeLoweredIntoVoidType, _BridgedSwiftGenericOptionalStackType { +public protocol _BridgedSwiftStruct: _BridgedSwiftTypeLoweredIntoVoidType, _BridgedSwiftStackType +where StackLiftResult == Self { // MARK: ExportSwift @_spi(BridgeJS) static func bridgeJSStackPop() -> Self @_spi(BridgeJS) consuming func bridgeJSStackPush() -> Void @@ -1227,7 +1277,9 @@ extension Optional { } } -public protocol _BridgedSwiftOptionalScalarBridge: _BridgedSwiftTypeLoweredIntoSingleWasmCoreType { +public protocol _BridgedSwiftOptionalScalarBridge: _BridgedSwiftTypeLoweredIntoSingleWasmCoreType, + _BridgedSwiftStackType +where StackLiftResult == Self { @_spi(BridgeJS) static func bridgeJSPopOptionalScalarPayload() -> WasmCoreType @_spi(BridgeJS) static var bridgeJSOptionalScalarNonePayload: WasmCoreType { get } @_spi(BridgeJS) static func bridgeJSWriteOptionalReturn(_ isSome: Int32, _ value: WasmCoreType) @@ -1324,12 +1376,6 @@ extension Optional where Wrapped: _BridgedSwiftOptionalScalarBridge { return Wrapped.bridgeJSLiftParameter(wrappedValue) } - @_spi(BridgeJS) public static func bridgeJSStackPop() -> Wrapped? { - let isSome = _swift_js_pop_i32() - let wrappedValue = Wrapped.bridgeJSPopOptionalScalarPayload() - return bridgeJSLiftParameter(isSome, wrappedValue) - } - @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void { switch consume self { case .none: @@ -1378,13 +1424,6 @@ extension Optional where Wrapped == String { _bridgeJSLiftParameter(isSome, (bytes, count), liftWrapped: { String.bridgeJSLiftParameter($0.0, $0.1) }) } - @_spi(BridgeJS) public static func bridgeJSStackPop() -> String? { - let isSome = _swift_js_pop_i32() - let bytes = _swift_js_pop_i32() - let count = _swift_js_pop_i32() - return bridgeJSLiftParameter(isSome, bytes, count) - } - @_spi(BridgeJS) public static func bridgeJSLiftReturnFromSideChannel() -> String? { let length = _swift_js_get_optional_string() if length < 0 { @@ -1418,12 +1457,6 @@ extension Optional where Wrapped == JSObject { _bridgeJSLiftParameter(isSome, objectId, liftWrapped: JSObject.bridgeJSLiftParameter) } - @_spi(BridgeJS) public static func bridgeJSStackPop() -> JSObject? { - let isSome = _swift_js_pop_i32() - let objectId = _swift_js_pop_i32() - return bridgeJSLiftParameter(isSome, objectId) - } - @_spi(BridgeJS) public func bridgeJSLowerReturn() -> Void { _bridgeJSLowerReturn( noneValue: 0, @@ -1466,32 +1499,14 @@ extension Optional where Wrapped == JSValue { } } - @_spi(BridgeJS) public static func bridgeJSLiftParameter() -> JSValue? { - let isSome = _swift_js_pop_i32() - if isSome == 0 { - return nil - } - let payload2 = _swift_js_pop_f64() - let payload1 = _swift_js_pop_i32() - let kind = _swift_js_pop_i32() - return JSValue.bridgeJSLiftParameter(kind, payload1, payload2) - } - - @_spi(BridgeJS) public func bridgeJSLowerReturn() -> Void { - switch self { - case .none: - _swift_js_push_i32(0) - case .some(let value): - value.bridgeJSLowerReturn() - _swift_js_push_i32(1) - } + @_spi(BridgeJS) public func bridgeJSLowerReturn() { + self.bridgeJSStackPush() } } -extension Optional where Wrapped == [JSValue] { - // MARK: ExportSwift - - @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 { +extension Optional { + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 + where Wrapped == [Element], Element: _BridgedSwiftStackType, Element == Element.StackLiftResult { switch consume self { case .none: return 0 @@ -1501,30 +1516,48 @@ extension Optional where Wrapped == [JSValue] { } } - @_spi(BridgeJS) public static func bridgeJSLiftParameter(_ isSome: Int32) -> [JSValue]? { - if isSome == 0 { - return nil - } - return [JSValue].bridgeJSLiftParameter() + @_spi(BridgeJS) public static func bridgeJSLiftParameter() -> [Element]? + where Wrapped == [Element], Element: _BridgedSwiftStackType, Element == Element.StackLiftResult { + return self.bridgeJSStackPop() } - @_spi(BridgeJS) public static func bridgeJSLiftReturn() -> [JSValue]? { - let isSome = _swift_js_pop_i32() - if isSome == 0 { - return nil - } - return [JSValue].bridgeJSLiftReturn() + @_spi(BridgeJS) public static func bridgeJSLiftReturn() -> [Element]? + where Wrapped == [Element], Element: _BridgedSwiftStackType, Element == Element.StackLiftResult { + return self.bridgeJSStackPop() } - @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void { + @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void + where Wrapped == [Element], Element: _BridgedSwiftStackType, Element == Element.StackLiftResult { + self.bridgeJSStackPush() + } +} + +extension Optional { + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 + where Wrapped == [String: Value], Value: _BridgedSwiftStackType, Value == Value.StackLiftResult { switch consume self { case .none: - _swift_js_push_i32(0) - case .some(let array): - array.bridgeJSLowerReturn() - _swift_js_push_i32(1) + return 0 + case .some(let value): + value.bridgeJSLowerReturn() + return 1 } } + + @_spi(BridgeJS) public static func bridgeJSLiftParameter() -> [String: Value]? + where Wrapped == [String: Value], Value: _BridgedSwiftStackType, Value == Value.StackLiftResult { + return self.bridgeJSStackPop() + } + + @_spi(BridgeJS) public static func bridgeJSLiftReturn() -> [String: Value]? + where Wrapped == [String: Value], Value: _BridgedSwiftStackType, Value == Value.StackLiftResult { + return self.bridgeJSStackPop() + } + + @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void + where Wrapped == [String: Value], Value: _BridgedSwiftStackType, Value == Value.StackLiftResult { + self.bridgeJSStackPush() + } } extension Optional where Wrapped: _BridgedSwiftProtocolWrapper { @@ -1583,12 +1616,6 @@ extension Optional where Wrapped: _BridgedSwiftHeapObject { _bridgeJSLiftParameter(isSome, pointer, liftWrapped: Wrapped.bridgeJSLiftParameter) } - @_spi(BridgeJS) public static func bridgeJSStackPop() -> Wrapped? { - let isSome = _swift_js_pop_i32() - let pointer = _swift_js_pop_pointer() - return bridgeJSLiftParameter(isSome, pointer) - } - @_spi(BridgeJS) public static func bridgeJSLiftReturnFromSideChannel() -> Wrapped? { let pointer = _swift_js_get_optional_heap_object_pointer() if pointer == UnsafeMutableRawPointer(bitPattern: 0) { @@ -1620,12 +1647,6 @@ extension Optional where Wrapped: _BridgedSwiftCaseEnum { _bridgeJSLiftParameter(isSome, wrappedValue, liftWrapped: Wrapped.bridgeJSLiftParameter) } - @_spi(BridgeJS) public static func bridgeJSStackPop() -> Wrapped? { - let isSome = _swift_js_pop_i32() - let wrappedValue = _swift_js_pop_i32() - return bridgeJSLiftParameter(isSome, wrappedValue) - } - @_spi(BridgeJS) public static func bridgeJSLiftReturn(_ value: Int32) -> Wrapped? { if value == -1 { return nil @@ -1687,12 +1708,6 @@ extension Optional where Wrapped: _BridgedSwiftEnumNoPayload, Wrapped: RawRepres let optionalRawValue: String? = self?.rawValue optionalRawValue.bridgeJSLowerReturn() } - @_spi(BridgeJS) public static func bridgeJSStackPop() -> Wrapped? { - let isSome = _swift_js_pop_i32() - let bytes = _swift_js_pop_i32() - let count = _swift_js_pop_i32() - return bridgeJSLiftParameter(isSome, bytes, count) - } } extension Optional where Wrapped: _BridgedSwiftEnumNoPayload, Wrapped: RawRepresentable, Wrapped.RawValue == Int { @@ -1711,12 +1726,6 @@ extension Optional where Wrapped: _BridgedSwiftEnumNoPayload, Wrapped: RawRepres return optionalRawValue.flatMap { Wrapped(rawValue: $0) } } - @_spi(BridgeJS) public static func bridgeJSStackPop() -> Wrapped? { - let isSome = _swift_js_pop_i32() - let wrappedValue = _swift_js_pop_i32() - return bridgeJSLiftParameter(isSome, wrappedValue) - } - @_spi(BridgeJS) public static func bridgeJSLiftReturnFromSideChannel() -> Wrapped? { let isSome = _swift_js_get_optional_int_presence() if isSome == 0 { @@ -1741,12 +1750,6 @@ extension Optional where Wrapped: _BridgedSwiftEnumNoPayload, Wrapped: RawRepres return optionalRawValue.flatMap { Wrapped(rawValue: $0) } } - @_spi(BridgeJS) public static func bridgeJSStackPop() -> Wrapped? { - let isSome = _swift_js_pop_i32() - let wrappedValue = _swift_js_pop_i32() - return bridgeJSLiftParameter(isSome, wrappedValue) - } - @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void { let optionalRawValue: Bool? = self?.rawValue optionalRawValue.bridgeJSLowerReturn() @@ -1772,12 +1775,6 @@ extension Optional where Wrapped: _BridgedSwiftEnumNoPayload, Wrapped: RawRepres return optionalRawValue.flatMap { Wrapped(rawValue: $0) } } - @_spi(BridgeJS) public static func bridgeJSStackPop() -> Wrapped? { - let isSome = _swift_js_pop_i32() - let wrappedValue = _swift_js_pop_f32() - return bridgeJSLiftParameter(isSome, wrappedValue) - } - @_spi(BridgeJS) public static func bridgeJSLiftReturnFromSideChannel() -> Wrapped? { let isSome = _swift_js_get_optional_float_presence() if isSome == 0 { @@ -1813,12 +1810,6 @@ extension Optional where Wrapped: _BridgedSwiftEnumNoPayload, Wrapped: RawRepres return optionalRawValue.flatMap { Wrapped(rawValue: $0) } } - @_spi(BridgeJS) public static func bridgeJSStackPop() -> Wrapped? { - let isSome = _swift_js_pop_i32() - let wrappedValue = _swift_js_pop_f64() - return bridgeJSLiftParameter(isSome, wrappedValue) - } - @_spi(BridgeJS) public static func bridgeJSLiftReturnFromSideChannel() -> Wrapped? { let isSome = _swift_js_get_optional_double_presence() if isSome == 0 { @@ -1838,22 +1829,6 @@ extension Optional where Wrapped: _BridgedSwiftEnumNoPayload, Wrapped: RawRepres // MARK: Optional Associated Value Enum Support extension Optional where Wrapped: _BridgedSwiftAssociatedValueEnum { - private static func bridgeJSStackPopPayload(_ discriminant: Int32) -> Wrapped? { - if discriminant == -1 { - return nil - } else { - return Wrapped.bridgeJSStackPopPayload(discriminant) - } - } - private consuming func bridgeJSStackPushPayload() -> Int32 { - switch consume self { - case .none: - return -1 - case .some(let value): - return value.bridgeJSStackPushPayload() - } - } - // MARK: ExportSwift @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> (isSome: Int32, caseId: Int32) { @@ -1874,27 +1849,16 @@ extension Optional where Wrapped: _BridgedSwiftAssociatedValueEnum { } @_spi(BridgeJS) public static func bridgeJSLiftReturn(_ caseId: Int32) -> Wrapped? { - return bridgeJSStackPopPayload(caseId) + if caseId == -1 { + return nil + } else { + return Wrapped.bridgeJSStackPopPayload(caseId) + } } @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() { bridgeJSStackPush() } - - @_spi(BridgeJS) public static func bridgeJSStackPop() -> Wrapped? { - let isSome = _swift_js_pop_i32() - let caseId = _swift_js_pop_i32() - return bridgeJSLiftParameter(isSome, caseId) - } - - @_spi(BridgeJS) public consuming func bridgeJSStackPush() -> Void { - switch consume self { - case .none: - _swift_js_push_i32(-1) // Use -1 as sentinel for null - case .some(let value): - value.bridgeJSStackPush() - } - } } // MARK: Optional Struct Support @@ -1907,53 +1871,45 @@ extension Optional where Wrapped: _BridgedSwiftStruct { return Wrapped.bridgeJSStackPop() } } + + @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void { + bridgeJSStackPush() + } + @_spi(BridgeJS) public static func bridgeJSLiftParameter() -> Wrapped? { - return bridgeJSStackPop() + bridgeJSStackPop() } } -// MARK: - Generic Optional Stack Support - -/// Marker protocol for types whose Optional wrapper should use the generic -/// stack-based ABI (`_BridgedSwiftStackType`). Only Array, Dictionary, and -/// `_BridgedSwiftStruct` conform. Primitives and other types keep their -/// own type-specific Optional extensions. -public protocol _BridgedSwiftGenericOptionalStackType: _BridgedSwiftStackType -where StackLiftResult == Self {} +// MARK: - Optional _BridgedSwiftStackType conformance +// The default push/pop implementation just goes through +// `_BridgedSwiftStackType.bridgeJSStackPushAsOptional`, but some +// Wrapped types (e.g. case enums) have a more efficient implementation. extension Optional: _BridgedSwiftStackType -where Wrapped: _BridgedSwiftGenericOptionalStackType { +where Wrapped: _BridgedSwiftStackType, Wrapped.StackLiftResult == Wrapped { public typealias StackLiftResult = Wrapped? @_spi(BridgeJS) public static func bridgeJSStackPop() -> Wrapped? { - let isSome = _swift_js_pop_i32() - if isSome == 0 { - return nil - } - return Wrapped.bridgeJSStackPop() + return Wrapped.bridgeJSStackPopAsOptional() } @_spi(BridgeJS) public consuming func bridgeJSStackPush() { - switch consume self { - case .none: - _swift_js_push_i32(0) - case .some(let value): - value.bridgeJSStackPush() - _swift_js_push_i32(1) - } + Wrapped.bridgeJSStackPushAsOptional(self) } +} - @_spi(BridgeJS) public static func bridgeJSLiftParameter() -> Wrapped? { - return bridgeJSStackPop() - } +// MARK: - _BridgedAsOptional (JSUndefinedOr) delegating to Optional - @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void { - bridgeJSStackPush() +extension _BridgedAsOptional where Wrapped: _BridgedSwiftStackType, Wrapped.StackLiftResult == Wrapped { + @_spi(BridgeJS) public static func bridgeJSStackPop() -> Self { + Self(optional: Optional.bridgeJSStackPop()) + } + @_spi(BridgeJS) public consuming func bridgeJSStackPush() { + asOptional.bridgeJSStackPush() } } -// MARK: - _BridgedAsOptional (JSUndefinedOr) delegating to Optional - extension _BridgedAsOptional where Wrapped: _BridgedSwiftOptionalScalarBridge { @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> ( isSome: Int32, value: Wrapped.WasmCoreType @@ -1968,10 +1924,6 @@ extension _BridgedAsOptional where Wrapped: _BridgedSwiftOptionalScalarBridge { Self(optional: Optional.bridgeJSLiftParameter(isSome, wrappedValue)) } - @_spi(BridgeJS) public static func bridgeJSStackPop() -> Self { - Self(optional: Optional.bridgeJSStackPop()) - } - @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void { asOptional.bridgeJSLowerReturn() } @@ -2002,10 +1954,6 @@ extension _BridgedAsOptional where Wrapped == String { Self(optional: Optional.bridgeJSLiftParameter(isSome, bytes, count)) } - @_spi(BridgeJS) public static func bridgeJSStackPop() -> Self { - Self(optional: Optional.bridgeJSStackPop()) - } - @_spi(BridgeJS) public static func bridgeJSLiftReturnFromSideChannel() -> Self { Self(optional: Optional.bridgeJSLiftReturnFromSideChannel()) } @@ -2024,10 +1972,6 @@ extension _BridgedAsOptional where Wrapped == JSObject { Self(optional: Optional.bridgeJSLiftParameter(isSome, objectId)) } - @_spi(BridgeJS) public static func bridgeJSStackPop() -> Self { - Self(optional: Optional.bridgeJSStackPop()) - } - @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void { asOptional.bridgeJSLowerReturn() } @@ -2056,10 +2000,6 @@ extension _BridgedAsOptional where Wrapped: _BridgedSwiftHeapObject { Self(optional: Optional.bridgeJSLiftParameter(isSome, pointer)) } - @_spi(BridgeJS) public static func bridgeJSStackPop() -> Self { - Self(optional: Optional.bridgeJSStackPop()) - } - @_spi(BridgeJS) public static func bridgeJSLiftReturnFromSideChannel() -> Self { Self(optional: Optional.bridgeJSLiftReturnFromSideChannel()) } @@ -2078,10 +2018,6 @@ extension _BridgedAsOptional where Wrapped: _BridgedSwiftCaseEnum { Self(optional: Optional.bridgeJSLiftParameter(isSome, caseId)) } - @_spi(BridgeJS) public static func bridgeJSStackPop() -> Self { - Self(optional: Optional.bridgeJSStackPop()) - } - @_spi(BridgeJS) public static func bridgeJSLiftReturn(_ caseId: Int32) -> Self { Self(optional: Optional.bridgeJSLiftReturn(caseId)) } @@ -2105,10 +2041,6 @@ where Wrapped: _BridgedSwiftEnumNoPayload, Wrapped: RawRepresentable, Wrapped.Ra Self(optional: Optional.bridgeJSLiftParameter(isSome, bytes, count)) } - @_spi(BridgeJS) public static func bridgeJSStackPop() -> Self { - Self(optional: Optional.bridgeJSStackPop()) - } - @_spi(BridgeJS) public static func bridgeJSLiftReturnFromSideChannel() -> Self { Self(optional: Optional.bridgeJSLiftReturnFromSideChannel()) } @@ -2128,10 +2060,6 @@ where Wrapped: _BridgedSwiftEnumNoPayload, Wrapped: RawRepresentable, Wrapped.Ra Self(optional: Optional.bridgeJSLiftParameter(isSome, wrappedValue)) } - @_spi(BridgeJS) public static func bridgeJSStackPop() -> Self { - Self(optional: Optional.bridgeJSStackPop()) - } - @_spi(BridgeJS) public static func bridgeJSLiftReturnFromSideChannel() -> Self { Self(optional: Optional.bridgeJSLiftReturnFromSideChannel()) } @@ -2147,10 +2075,6 @@ where Wrapped: _BridgedSwiftEnumNoPayload, Wrapped: RawRepresentable, Wrapped.Ra Self(optional: Optional.bridgeJSLiftParameter(isSome, wrappedValue)) } - @_spi(BridgeJS) public static func bridgeJSStackPop() -> Self { - Self(optional: Optional.bridgeJSStackPop()) - } - @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void { asOptional.bridgeJSLowerReturn() } @@ -2166,10 +2090,6 @@ where Wrapped: _BridgedSwiftEnumNoPayload, Wrapped: RawRepresentable, Wrapped.Ra Self(optional: Optional.bridgeJSLiftParameter(isSome, wrappedValue)) } - @_spi(BridgeJS) public static func bridgeJSStackPop() -> Self { - Self(optional: Optional.bridgeJSStackPop()) - } - @_spi(BridgeJS) public static func bridgeJSLiftReturnFromSideChannel() -> Self { Self(optional: Optional.bridgeJSLiftReturnFromSideChannel()) } @@ -2189,10 +2109,6 @@ where Wrapped: _BridgedSwiftEnumNoPayload, Wrapped: RawRepresentable, Wrapped.Ra Self(optional: Optional.bridgeJSLiftParameter(isSome, wrappedValue)) } - @_spi(BridgeJS) public static func bridgeJSStackPop() -> Self { - Self(optional: Optional.bridgeJSStackPop()) - } - @_spi(BridgeJS) public static func bridgeJSLiftReturnFromSideChannel() -> Self { Self(optional: Optional.bridgeJSLiftReturnFromSideChannel()) } @@ -2211,10 +2127,6 @@ extension _BridgedAsOptional where Wrapped: _BridgedSwiftAssociatedValueEnum { Self(optional: Optional.bridgeJSLiftParameter(isSome, caseId)) } - @_spi(BridgeJS) public static func bridgeJSStackPop() -> Self { - Self(optional: Optional.bridgeJSStackPop()) - } - @_spi(BridgeJS) public static func bridgeJSLiftReturn(_ caseId: Int32) -> Self { Self(optional: Optional.bridgeJSLiftReturn(caseId)) } @@ -2232,20 +2144,10 @@ extension _BridgedAsOptional where Wrapped: _BridgedSwiftStruct { @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void { asOptional.bridgeJSLowerReturn() } - - // MARK: Stack ABI - @_spi(BridgeJS) public static func bridgeJSStackPop() -> Self { - Self(optional: Optional.bridgeJSStackPop()) - } - @_spi(BridgeJS) public consuming func bridgeJSStackPush() { - asOptional.bridgeJSStackPush() - } } // MARK: - Array Support -extension Array: _BridgedSwiftGenericOptionalStackType -where Element: _BridgedSwiftStackType, Element.StackLiftResult == Element {} extension Array: _BridgedSwiftStackType where Element: _BridgedSwiftStackType, Element.StackLiftResult == Element { public typealias StackLiftResult = [Element] @@ -2286,14 +2188,12 @@ extension Array: _BridgedSwiftStackType where Element: _BridgedSwiftStackType, E // MARK: - Dictionary Support public protocol _BridgedSwiftDictionaryStackType: _BridgedSwiftTypeLoweredIntoVoidType, - _BridgedSwiftGenericOptionalStackType -{ + _BridgedSwiftStackType +where StackLiftResult == Self { associatedtype DictionaryValue: _BridgedSwiftStackType where DictionaryValue.StackLiftResult == DictionaryValue } -extension Dictionary: _BridgedSwiftGenericOptionalStackType -where Key == String, Value: _BridgedSwiftStackType, Value.StackLiftResult == Value {} extension Dictionary: _BridgedSwiftStackType where Key == String, Value: _BridgedSwiftStackType, Value.StackLiftResult == Value { public typealias StackLiftResult = [String: Value] @@ -2372,6 +2272,10 @@ extension Optional where Wrapped: _BridgedSwiftDictionaryStackType { @_spi(BridgeJS) public static func bridgeJSLiftReturn() -> [String: Wrapped.DictionaryValue]? { return bridgeJSStackPopPayload(_swift_js_pop_i32()) } + + @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void { + bridgeJSStackPush() + } } extension _BridgedAsOptional where Wrapped: _BridgedSwiftDictionaryStackType { diff --git a/Tests/BridgeJSRuntimeTests/ArraySupportTests.swift b/Tests/BridgeJSRuntimeTests/ArraySupportTests.swift index ea4ffea44..e4875486a 100644 --- a/Tests/BridgeJSRuntimeTests/ArraySupportTests.swift +++ b/Tests/BridgeJSRuntimeTests/ArraySupportTests.swift @@ -16,10 +16,6 @@ import JavaScriptKit @JSFunction static func jsRoundTripBoolArray(_ values: [Bool]) throws(JSException) -> [Bool] @JSFunction static func jsRoundTripJSValueArray(_ v: [JSValue]) throws(JSException) -> [JSValue] - @JSFunction static func jsRoundTripOptionalJSValueArray( - _ v: Optional<[JSValue]> - ) throws(JSException) -> Optional<[JSValue]> - @JSFunction static func jsRoundTripJSObjectArray(_ values: [JSObject]) throws(JSException) -> [JSObject] @JSFunction static func jsRoundTripJSClassArray( @@ -93,13 +89,6 @@ final class ArraySupportTests: XCTestCase { XCTAssertEqual(try ArraySupportImports.jsRoundTripJSValueArray([]), []) } - func testRoundTripOptionalJSValueArray() throws { - XCTAssertNil(try ArraySupportImports.jsRoundTripOptionalJSValueArray(nil)) - let values: [JSValue] = [.number(1), .undefined, .null] - let result = try ArraySupportImports.jsRoundTripOptionalJSValueArray(values) - XCTAssertEqual(result, values) - } - func testRoundTripJSObjectArray() throws { let values: [JSObject] = [.global, JSObject(), ["a": 1, "b": 2]] let result = try ArraySupportImports.jsRoundTripJSObjectArray(values) diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift index 8acb0a347..048400d42 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift @@ -2689,18 +2689,10 @@ extension TypedPayloadResult: _BridgedSwiftAssociatedValueEnum { param0.bridgeJSStackPush() return Int32(1) case .optPrecision(let param0): - let __bjs_isSome_param0 = param0 != nil - if let __bjs_unwrapped_param0 = param0 { - __bjs_unwrapped_param0.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_param0 ? 1 : 0) + param0.bridgeJSStackPush() return Int32(2) case .optDirection(let param0): - let __bjs_isSome_param0 = param0 != nil - if let __bjs_unwrapped_param0 = param0 { - __bjs_unwrapped_param0.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_param0 ? 1 : 0) + param0.bridgeJSStackPush() return Int32(3) case .empty: return Int32(4) @@ -3041,35 +3033,19 @@ extension OptionalAllTypesResult: _BridgedSwiftAssociatedValueEnum { param0.bridgeJSStackPush() return Int32(0) case .optClass(let param0): - let __bjs_isSome_param0 = param0 != nil - if let __bjs_unwrapped_param0 = param0 { - __bjs_unwrapped_param0.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_param0 ? 1 : 0) + param0.bridgeJSStackPush() return Int32(1) case .optJSObject(let param0): - let __bjs_isSome_param0 = param0 != nil - if let __bjs_unwrapped_param0 = param0 { - __bjs_unwrapped_param0.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_param0 ? 1 : 0) + param0.bridgeJSStackPush() return Int32(2) case .optNestedEnum(let param0): - let __bjs_isSome_param0 = param0 != nil - if let __bjs_unwrapped_param0 = param0 { - __bjs_unwrapped_param0.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_param0 ? 1 : 0) + param0.bridgeJSStackPush() return Int32(3) case .optArray(let param0): param0.bridgeJSStackPush() return Int32(4) case .optJsClass(let param0): - let __bjs_isSome_param0 = param0 != nil - if let __bjs_unwrapped_param0 = param0 { - __bjs_unwrapped_param0.jsObject.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_param0 ? 1 : 0) + param0.bridgeJSStackPush() return Int32(5) case .empty: return Int32(6) @@ -3094,40 +3070,16 @@ extension APIOptionalResult: _BridgedSwiftAssociatedValueEnum { @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPushPayload() -> Int32 { switch self { case .success(let param0): - let __bjs_isSome_param0 = param0 != nil - if let __bjs_unwrapped_param0 = param0 { - __bjs_unwrapped_param0.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_param0 ? 1 : 0) + param0.bridgeJSStackPush() return Int32(0) case .failure(let param0, let param1): - let __bjs_isSome_param0 = param0 != nil - if let __bjs_unwrapped_param0 = param0 { - __bjs_unwrapped_param0.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_param0 ? 1 : 0) - let __bjs_isSome_param1 = param1 != nil - if let __bjs_unwrapped_param1 = param1 { - __bjs_unwrapped_param1.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_param1 ? 1 : 0) + param0.bridgeJSStackPush() + param1.bridgeJSStackPush() return Int32(1) case .status(let param0, let param1, let param2): - let __bjs_isSome_param0 = param0 != nil - if let __bjs_unwrapped_param0 = param0 { - __bjs_unwrapped_param0.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_param0 ? 1 : 0) - let __bjs_isSome_param1 = param1 != nil - if let __bjs_unwrapped_param1 = param1 { - __bjs_unwrapped_param1.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_param1 ? 1 : 0) - let __bjs_isSome_param2 = param2 != nil - if let __bjs_unwrapped_param2 = param2 { - __bjs_unwrapped_param2.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_param2 ? 1 : 0) + param0.bridgeJSStackPush() + param1.bridgeJSStackPush() + param2.bridgeJSStackPush() return Int32(2) } } @@ -3260,16 +3212,8 @@ extension DataPoint: _BridgedSwiftStruct { self.x.bridgeJSStackPush() self.y.bridgeJSStackPush() self.label.bridgeJSStackPush() - let __bjs_isSome_optCount = self.optCount != nil - if let __bjs_unwrapped_optCount = self.optCount { - __bjs_unwrapped_optCount.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_optCount ? 1 : 0) - let __bjs_isSome_optFlag = self.optFlag != nil - if let __bjs_unwrapped_optFlag = self.optFlag { - __bjs_unwrapped_optFlag.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_optFlag ? 1 : 0) + self.optCount.bridgeJSStackPush() + self.optFlag.bridgeJSStackPush() } init(unsafelyCopying jsObject: JSObject) { @@ -3389,11 +3333,7 @@ extension Address: _BridgedSwiftStruct { @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() { self.street.bridgeJSStackPush() self.city.bridgeJSStackPush() - let __bjs_isSome_zipCode = self.zipCode != nil - if let __bjs_unwrapped_zipCode = self.zipCode { - __bjs_unwrapped_zipCode.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_zipCode ? 1 : 0) + self.zipCode.bridgeJSStackPush() } init(unsafelyCopying jsObject: JSObject) { @@ -3446,11 +3386,7 @@ extension Contact: _BridgedSwiftStruct { self.name.bridgeJSStackPush() self.age.bridgeJSStackPush() self.address.bridgeJSStackPush() - let __bjs_isSome_email = self.email != nil - if let __bjs_unwrapped_email = self.email { - __bjs_unwrapped_email.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_email ? 1 : 0) + self.email.bridgeJSStackPush() self.secondaryAddress.bridgeJSStackPush() } @@ -3501,16 +3437,8 @@ extension Config: _BridgedSwiftStruct { @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() { self.name.bridgeJSStackPush() - let __bjs_isSome_theme = self.theme != nil - if let __bjs_unwrapped_theme = self.theme { - __bjs_unwrapped_theme.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_theme ? 1 : 0) - let __bjs_isSome_direction = self.direction != nil - if let __bjs_unwrapped_direction = self.direction { - __bjs_unwrapped_direction.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_direction ? 1 : 0) + self.theme.bridgeJSStackPush() + self.direction.bridgeJSStackPush() self.status.bridgeJSStackPush() } @@ -3559,11 +3487,7 @@ extension SessionData: _BridgedSwiftStruct { @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() { self.id.bridgeJSStackPush() - let __bjs_isSome_owner = self.owner != nil - if let __bjs_unwrapped_owner = self.owner { - __bjs_unwrapped_owner.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_owner ? 1 : 0) + self.owner.bridgeJSStackPush() } init(unsafelyCopying jsObject: JSObject) { @@ -3614,16 +3538,8 @@ extension ValidationReport: _BridgedSwiftStruct { @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() { self.id.bridgeJSStackPush() self.result.bridgeJSStackPush() - let __bjs_isSome_status = self.status != nil - if let __bjs_unwrapped_status = self.status { - __bjs_unwrapped_status.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_status ? 1 : 0) - let __bjs_isSome_outcome = self.outcome != nil - if let __bjs_unwrapped_outcome = self.outcome { - __bjs_unwrapped_outcome.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_outcome ? 1 : 0) + self.status.bridgeJSStackPush() + self.outcome.bridgeJSStackPush() } init(unsafelyCopying jsObject: JSObject) { @@ -3683,16 +3599,8 @@ extension AdvancedConfig: _BridgedSwiftStruct { self.enabled.bridgeJSStackPush() self.theme.bridgeJSStackPush() self.status.bridgeJSStackPush() - let __bjs_isSome_result = self.result != nil - if let __bjs_unwrapped_result = self.result { - __bjs_unwrapped_result.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_result ? 1 : 0) - let __bjs_isSome_metadata = self.metadata != nil - if let __bjs_unwrapped_metadata = self.metadata { - __bjs_unwrapped_metadata.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_metadata ? 1 : 0) + self.result.bridgeJSStackPush() + self.metadata.bridgeJSStackPush() self.location.bridgeJSStackPush() self.defaults.bridgeJSStackPush() self.overrideDefaults.bridgeJSStackPush() @@ -3746,16 +3654,8 @@ extension MeasurementConfig: _BridgedSwiftStruct { @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() { self.precision.bridgeJSStackPush() self.ratio.bridgeJSStackPush() - let __bjs_isSome_optionalPrecision = self.optionalPrecision != nil - if let __bjs_unwrapped_optionalPrecision = self.optionalPrecision { - __bjs_unwrapped_optionalPrecision.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_optionalPrecision ? 1 : 0) - let __bjs_isSome_optionalRatio = self.optionalRatio != nil - if let __bjs_unwrapped_optionalRatio = self.optionalRatio { - __bjs_unwrapped_optionalRatio.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_optionalRatio ? 1 : 0) + self.optionalPrecision.bridgeJSStackPush() + self.optionalRatio.bridgeJSStackPush() } init(unsafelyCopying jsObject: JSObject) { @@ -3893,11 +3793,7 @@ extension CopyableCart: _BridgedSwiftStruct { @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() { self.x.bridgeJSStackPush() - let __bjs_isSome_note = self.note != nil - if let __bjs_unwrapped_note = self.note { - __bjs_unwrapped_note.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_note ? 1 : 0) + self.note.bridgeJSStackPush() } init(unsafelyCopying jsObject: JSObject) { @@ -4177,11 +4073,7 @@ extension JSObjectContainer: _BridgedSwiftStruct { @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() { self.object.bridgeJSStackPush() - let __bjs_isSome_optionalObject = self.optionalObject != nil - if let __bjs_unwrapped_optionalObject = self.optionalObject { - __bjs_unwrapped_optionalObject.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_optionalObject ? 1 : 0) + self.optionalObject.bridgeJSStackPush() } init(unsafelyCopying jsObject: JSObject) { @@ -4229,11 +4121,7 @@ extension FooContainer: _BridgedSwiftStruct { @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() { self.foo.jsObject.bridgeJSStackPush() - let __bjs_isSome_optionalFoo = self.optionalFoo != nil - if let __bjs_unwrapped_optionalFoo = self.optionalFoo { - __bjs_unwrapped_optionalFoo.jsObject.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_optionalFoo ? 1 : 0) + self.optionalFoo.bridgeJSStackPush() } init(unsafelyCopying jsObject: JSObject) { @@ -5815,11 +5703,7 @@ public func _bjs_roundTripOptionalIntArray() -> Void { return __result }()) for __bjs_elem_ret in ret { - let __bjs_isSome_ret_elem = __bjs_elem_ret != nil - if let __bjs_unwrapped_ret_elem = __bjs_elem_ret { - __bjs_unwrapped_ret_elem.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_ret_elem ? 1 : 0) + __bjs_elem_ret.bridgeJSStackPush() } _swift_js_push_i32(Int32(ret.count)) #else @@ -5842,11 +5726,7 @@ public func _bjs_roundTripOptionalStringArray() -> Void { return __result }()) for __bjs_elem_ret in ret { - let __bjs_isSome_ret_elem = __bjs_elem_ret != nil - if let __bjs_unwrapped_ret_elem = __bjs_elem_ret { - __bjs_unwrapped_ret_elem.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_ret_elem ? 1 : 0) + __bjs_elem_ret.bridgeJSStackPush() } _swift_js_push_i32(Int32(ret.count)) #else @@ -5892,11 +5772,7 @@ public func _bjs_roundTripOptionalDirectionArray() -> Void { return __result }()) for __bjs_elem_ret in ret { - let __bjs_isSome_ret_elem = __bjs_elem_ret != nil - if let __bjs_unwrapped_ret_elem = __bjs_elem_ret { - __bjs_unwrapped_ret_elem.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_ret_elem ? 1 : 0) + __bjs_elem_ret.bridgeJSStackPush() } _swift_js_push_i32(Int32(ret.count)) #else @@ -5919,11 +5795,7 @@ public func _bjs_roundTripOptionalStatusArray() -> Void { return __result }()) for __bjs_elem_ret in ret { - let __bjs_isSome_ret_elem = __bjs_elem_ret != nil - if let __bjs_unwrapped_ret_elem = __bjs_elem_ret { - __bjs_unwrapped_ret_elem.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_ret_elem ? 1 : 0) + __bjs_elem_ret.bridgeJSStackPush() } _swift_js_push_i32(Int32(ret.count)) #else @@ -6144,11 +6016,7 @@ public func _bjs_roundTripOptionalJSObjectArray() -> Void { return __result }()) for __bjs_elem_ret in ret { - let __bjs_isSome_ret_elem = __bjs_elem_ret != nil - if let __bjs_unwrapped_ret_elem = __bjs_elem_ret { - __bjs_unwrapped_ret_elem.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_ret_elem ? 1 : 0) + __bjs_elem_ret.bridgeJSStackPush() } _swift_js_push_i32(Int32(ret.count)) #else @@ -6182,11 +6050,7 @@ public func _bjs_roundTripOptionalFooArray() -> Void { return __result }()) for __bjs_elem_ret in ret { - let __bjs_isSome_ret_elem = __bjs_elem_ret != nil - if let __bjs_unwrapped_ret_elem = __bjs_elem_ret { - __bjs_unwrapped_ret_elem.jsObject.bridgeJSStackPush() - } - _swift_js_push_i32(__bjs_isSome_ret_elem ? 1 : 0) + __bjs_elem_ret.bridgeJSStackPush() } _swift_js_push_i32(Int32(ret.count)) #else @@ -9511,18 +9375,6 @@ fileprivate func bjs_ArraySupportImports_jsRoundTripJSValueArray_static_extern() return bjs_ArraySupportImports_jsRoundTripJSValueArray_static_extern() } -#if arch(wasm32) -@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_ArraySupportImports_jsRoundTripOptionalJSValueArray_static") -fileprivate func bjs_ArraySupportImports_jsRoundTripOptionalJSValueArray_static_extern(_ v: Int32) -> Void -#else -fileprivate func bjs_ArraySupportImports_jsRoundTripOptionalJSValueArray_static_extern(_ v: Int32) -> Void { - fatalError("Only available on WebAssembly") -} -#endif -@inline(never) fileprivate func bjs_ArraySupportImports_jsRoundTripOptionalJSValueArray_static(_ v: Int32) -> Void { - return bjs_ArraySupportImports_jsRoundTripOptionalJSValueArray_static_extern(v) -} - #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_ArraySupportImports_jsRoundTripJSObjectArray_static") fileprivate func bjs_ArraySupportImports_jsRoundTripJSObjectArray_static_extern() -> Void @@ -9625,15 +9477,6 @@ func _$ArraySupportImports_jsRoundTripJSValueArray(_ v: [JSValue]) throws(JSExce return [JSValue].bridgeJSLiftReturn() } -func _$ArraySupportImports_jsRoundTripOptionalJSValueArray(_ v: Optional<[JSValue]>) throws(JSException) -> Optional<[JSValue]> { - let vIsSome = v.bridgeJSLowerParameter() - bjs_ArraySupportImports_jsRoundTripOptionalJSValueArray_static(vIsSome) - if let error = _swift_js_take_exception() { - throw error - } - return Optional<[JSValue]>.bridgeJSLiftReturn() -} - func _$ArraySupportImports_jsRoundTripJSObjectArray(_ values: [JSObject]) throws(JSException) -> [JSObject] { let _ = values.bridgeJSLowerParameter() bjs_ArraySupportImports_jsRoundTripJSObjectArray_static() @@ -11445,6 +11288,30 @@ fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalStringUndefined_s return bjs_OptionalSupportImports_jsRoundTripOptionalStringUndefined_static_extern(nameIsSome, nameValue) } +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_OptionalSupportImports_jsRoundTripOptionalJSValueArrayNull_static") +fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalJSValueArrayNull_static_extern(_ v: Int32) -> Void +#else +fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalJSValueArrayNull_static_extern(_ v: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalJSValueArrayNull_static(_ v: Int32) -> Void { + return bjs_OptionalSupportImports_jsRoundTripOptionalJSValueArrayNull_static_extern(v) +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_OptionalSupportImports_jsRoundTripOptionalStringToStringDictionaryNull_static") +fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalStringToStringDictionaryNull_static_extern(_ v: Int32) -> Void +#else +fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalStringToStringDictionaryNull_static_extern(_ v: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalStringToStringDictionaryNull_static(_ v: Int32) -> Void { + return bjs_OptionalSupportImports_jsRoundTripOptionalStringToStringDictionaryNull_static_extern(v) +} + #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_OptionalSupportImports_runJsOptionalSupportTests_static") fileprivate func bjs_OptionalSupportImports_runJsOptionalSupportTests_static_extern() -> Void @@ -11493,6 +11360,24 @@ func _$OptionalSupportImports_jsRoundTripOptionalStringUndefined(_ name: JSUndef return JSUndefinedOr.bridgeJSLiftReturnFromSideChannel() } +func _$OptionalSupportImports_jsRoundTripOptionalJSValueArrayNull(_ v: Optional<[JSValue]>) throws(JSException) -> Optional<[JSValue]> { + let vIsSome = v.bridgeJSLowerParameter() + bjs_OptionalSupportImports_jsRoundTripOptionalJSValueArrayNull_static(vIsSome) + if let error = _swift_js_take_exception() { + throw error + } + return Optional<[JSValue]>.bridgeJSLiftReturn() +} + +func _$OptionalSupportImports_jsRoundTripOptionalStringToStringDictionaryNull(_ v: Optional<[String: String]>) throws(JSException) -> Optional<[String: String]> { + let vIsSome = v.bridgeJSLowerParameter() + bjs_OptionalSupportImports_jsRoundTripOptionalStringToStringDictionaryNull_static(vIsSome) + if let error = _swift_js_take_exception() { + throw error + } + return Optional<[String: String]>.bridgeJSLiftReturn() +} + func _$OptionalSupportImports_runJsOptionalSupportTests() throws(JSException) -> Void { bjs_OptionalSupportImports_runJsOptionalSupportTests_static() if let error = _swift_js_take_exception() { diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json index 42b6abfbb..4b33632b5 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json @@ -13996,42 +13996,6 @@ } } }, - { - "name" : "jsRoundTripOptionalJSValueArray", - "parameters" : [ - { - "name" : "v", - "type" : { - "nullable" : { - "_0" : { - "array" : { - "_0" : { - "jsValue" : { - - } - } - } - }, - "_1" : "null" - } - } - } - ], - "returnType" : { - "nullable" : { - "_0" : { - "array" : { - "_0" : { - "jsValue" : { - - } - } - } - }, - "_1" : "null" - } - } - }, { "name" : "jsRoundTripJSObjectArray", "parameters" : [ @@ -16118,6 +16082,78 @@ } } }, + { + "name" : "jsRoundTripOptionalJSValueArrayNull", + "parameters" : [ + { + "name" : "v", + "type" : { + "nullable" : { + "_0" : { + "array" : { + "_0" : { + "jsValue" : { + + } + } + } + }, + "_1" : "null" + } + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "array" : { + "_0" : { + "jsValue" : { + + } + } + } + }, + "_1" : "null" + } + } + }, + { + "name" : "jsRoundTripOptionalStringToStringDictionaryNull", + "parameters" : [ + { + "name" : "v", + "type" : { + "nullable" : { + "_0" : { + "dictionary" : { + "_0" : { + "string" : { + + } + } + } + }, + "_1" : "null" + } + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "dictionary" : { + "_0" : { + "string" : { + + } + } + } + }, + "_1" : "null" + } + } + }, { "name" : "runJsOptionalSupportTests", "parameters" : [ diff --git a/Tests/BridgeJSRuntimeTests/JavaScript/OptionalSupportTests.mjs b/Tests/BridgeJSRuntimeTests/JavaScript/OptionalSupportTests.mjs index 58215560c..1a41cc43f 100644 --- a/Tests/BridgeJSRuntimeTests/JavaScript/OptionalSupportTests.mjs +++ b/Tests/BridgeJSRuntimeTests/JavaScript/OptionalSupportTests.mjs @@ -32,6 +32,12 @@ export function getImports(importsContext) { jsRoundTripOptionalStringUndefined: (v) => { return v === undefined ? undefined : v; }, + jsRoundTripOptionalJSValueArrayNull: (v) => { + return v ?? null; + }, + jsRoundTripOptionalStringToStringDictionaryNull: (v) => { + return v ?? null; + }, runJsOptionalSupportTests: () => { const exports = importsContext.getExports(); if (!exports) { throw new Error("No exports!?"); } diff --git a/Tests/BridgeJSRuntimeTests/OptionalSupportTests.swift b/Tests/BridgeJSRuntimeTests/OptionalSupportTests.swift index a99bb0bb1..c8cc9894b 100644 --- a/Tests/BridgeJSRuntimeTests/OptionalSupportTests.swift +++ b/Tests/BridgeJSRuntimeTests/OptionalSupportTests.swift @@ -10,6 +10,20 @@ import JavaScriptEventLoop _ name: JSUndefinedOr ) throws -> JSUndefinedOr + @JSFunction static func jsRoundTripOptionalJSValueArrayNull( + _ v: Optional<[JSValue]> + ) throws(JSException) -> Optional<[JSValue]> + // @JSFunction static func jsRoundTripOptionalJSValueArrayUndefined( + // _ v: JSUndefinedOr<[JSValue]> + // ) throws(JSException) -> JSUndefinedOr<[JSValue]> + + @JSFunction static func jsRoundTripOptionalStringToStringDictionaryNull( + _ v: Optional<[String: String]> + ) throws(JSException) -> Optional<[String: String]> + // @JSFunction static func jsRoundTripOptionalStringToStringDictionaryUndefined( + // _ v: JSUndefinedOr<[String: String]> + // ) throws(JSException) -> JSUndefinedOr<[String: String]> + @JSFunction static func runJsOptionalSupportTests() throws(JSException) } @@ -51,6 +65,22 @@ final class OptionalSupportTests: XCTestCase { func testRoundTripOptionalNumberUndefined() throws { try roundTripTest(OptionalSupportImports.jsRoundTripOptionalNumberUndefined, 42) } + + func testRoundTripOptionalJSValueArrayNull() throws { + try roundTripTest(OptionalSupportImports.jsRoundTripOptionalJSValueArrayNull, [.number(1), .undefined, .null]) + } + + // func testRoundTripOptionalJSValueArrayUndefined() throws { + // try roundTripTest(OptionalSupportImports.jsRoundTripOptionalJSValueArrayUndefined, [.number(1), .undefined, .null]) + // } + + func testRoundTripOptionalStringToStringDictionaryNull() throws { + try roundTripTest(OptionalSupportImports.jsRoundTripOptionalStringToStringDictionaryNull, ["key": "value"]) + } + + // func testRoundTripOptionalStringToStringDictionaryUndefined() throws { + // try roundTripTest(OptionalSupportImports.jsRoundTripOptionalStringToStringDictionaryUndefined, ["key": "value"]) + // } } // MARK: - Optional Bridging