Skip to content

Commit e68dcfb

Browse files
committed
BridgeJS: Fix issue with multiple stack-based parameters that require reversed order and intermediate properties
1 parent 15974c7 commit e68dcfb

File tree

7 files changed

+119
-2
lines changed

7 files changed

+119
-2
lines changed

Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1667,6 +1667,7 @@ public class ExportSwift {
16671667
}
16681668

16691669
func call(name: String, returnType: BridgeType) {
1670+
generateParameterLifting()
16701671
let item = renderCallStatement(callee: "\(raw: name)", returnType: returnType)
16711672
append(item)
16721673
}
@@ -1694,6 +1695,7 @@ public class ExportSwift {
16941695

16951696
func callMethod(klassName: String, methodName: String, returnType: BridgeType) {
16961697
let (_, selfExpr) = removeFirstLiftedParameter()
1698+
generateParameterLifting()
16971699
let item = renderCallStatement(
16981700
callee: "\(raw: selfExpr).\(raw: methodName)",
16991701
returnType: returnType
@@ -1827,6 +1829,29 @@ public class ExportSwift {
18271829
func returnSignature() -> String {
18281830
return abiReturnType?.swiftType ?? "Void"
18291831
}
1832+
1833+
/// Generates intermediate variables for stack-using parameters if needed for LIFO compatibility
1834+
private func generateParameterLifting() {
1835+
let stackParamIndices = parameters.enumerated().compactMap { index, param -> Int? in
1836+
switch param.type {
1837+
case .optional(.associatedValueEnum):
1838+
return index
1839+
default:
1840+
return nil
1841+
}
1842+
}
1843+
1844+
guard stackParamIndices.count > 1 else { return }
1845+
1846+
for index in stackParamIndices.reversed() {
1847+
let param = parameters[index]
1848+
let expr = liftedParameterExprs[index]
1849+
let varName = "_tmp_\(param.name)"
1850+
1851+
append("let \(raw: varName) = \(expr)")
1852+
liftedParameterExprs[index] = ExprSyntax(DeclReferenceExprSyntax(baseName: .identifier(varName)))
1853+
}
1854+
}
18301855
}
18311856

18321857
private struct ClosureCodegen {

Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/EnumAssociatedValue.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ enum Utilities {
4545
case failure(String, Int)
4646
}
4747

48-
@JS func roundTripOptionalNetworkingResult(result: NetworkingResult?) -> NetworkingResult?
48+
@JS func roundTripOptionalNetworkingResult(result: NetworkingResult?) -> NetworkingResult?
4949

5050
@JS
5151
enum APIOptionalResult {

Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumAssociatedValue.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -612,7 +612,9 @@ public func _bjs_roundTripOptionalAPIOptionalResult(resultIsSome: Int32, resultC
612612
@_cdecl("bjs_compareAPIResults")
613613
public func _bjs_compareAPIResults(result1IsSome: Int32, result1CaseId: Int32, result2IsSome: Int32, result2CaseId: Int32) -> Void {
614614
#if arch(wasm32)
615-
let ret = compareAPIResults(result1: Optional<APIOptionalResult>.bridgeJSLiftParameter(result1IsSome, result1CaseId), result2: Optional<APIOptionalResult>.bridgeJSLiftParameter(result2IsSome, result2CaseId))
615+
let _tmp_result2 = Optional<APIOptionalResult>.bridgeJSLiftParameter(result2IsSome, result2CaseId)
616+
let _tmp_result1 = Optional<APIOptionalResult>.bridgeJSLiftParameter(result1IsSome, result1CaseId)
617+
let ret = compareAPIResults(result1: _tmp_result1, result2: _tmp_result2)
616618
return ret.bridgeJSLowerReturn()
617619
#else
618620
fatalError("Only available on WebAssembly")

Tests/BridgeJSRuntimeTests/ExportAPITests.swift

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,32 @@ typealias OptionalAge = Int?
528528
return value
529529
}
530530

531+
@JS func compareAPIResults(_ r1: APIResult?, _ r2: APIResult?) -> String {
532+
let r1Str: String
533+
switch r1 {
534+
case .none: r1Str = "nil"
535+
case .some(.success(let msg)): r1Str = "success:\(msg)"
536+
case .some(.failure(let code)): r1Str = "failure:\(code)"
537+
case .some(.info): r1Str = "info"
538+
case .some(.flag(let b)): r1Str = "flag:\(b)"
539+
case .some(.rate(let r)): r1Str = "rate:\(r)"
540+
case .some(.precise(let p)): r1Str = "precise:\(p)"
541+
}
542+
543+
let r2Str: String
544+
switch r2 {
545+
case .none: r2Str = "nil"
546+
case .some(.success(let msg)): r2Str = "success:\(msg)"
547+
case .some(.failure(let code)): r2Str = "failure:\(code)"
548+
case .some(.info): r2Str = "info"
549+
case .some(.flag(let b)): r2Str = "flag:\(b)"
550+
case .some(.rate(let r)): r2Str = "rate:\(r)"
551+
case .some(.precise(let p)): r2Str = "precise:\(p)"
552+
}
553+
554+
return "r1:\(r1Str),r2:\(r2Str)"
555+
}
556+
531557
@JS func roundTripOptionalComplexResult(_ result: ComplexResult?) -> ComplexResult? {
532558
return result
533559
}

Tests/BridgeJSRuntimeTests/Generated/BridgeJS.ExportSwift.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3079,6 +3079,19 @@ public func _bjs_roundTripOptionalAPIResult(valueIsSome: Int32, valueCaseId: Int
30793079
#endif
30803080
}
30813081

3082+
@_expose(wasm, "bjs_compareAPIResults")
3083+
@_cdecl("bjs_compareAPIResults")
3084+
public func _bjs_compareAPIResults(r1IsSome: Int32, r1CaseId: Int32, r2IsSome: Int32, r2CaseId: Int32) -> Void {
3085+
#if arch(wasm32)
3086+
let _tmp_r2 = Optional<APIResult>.bridgeJSLiftParameter(r2IsSome, r2CaseId)
3087+
let _tmp_r1 = Optional<APIResult>.bridgeJSLiftParameter(r1IsSome, r1CaseId)
3088+
let ret = compareAPIResults(_: _tmp_r1, _: _tmp_r2)
3089+
return ret.bridgeJSLowerReturn()
3090+
#else
3091+
fatalError("Only available on WebAssembly")
3092+
#endif
3093+
}
3094+
30823095
@_expose(wasm, "bjs_roundTripOptionalComplexResult")
30833096
@_cdecl("bjs_roundTripOptionalComplexResult")
30843097
public func _bjs_roundTripOptionalComplexResult(resultIsSome: Int32, resultCaseId: Int32) -> Void {

Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.ExportSwift.json

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6826,6 +6826,48 @@
68266826
}
68276827
}
68286828
},
6829+
{
6830+
"abiName" : "bjs_compareAPIResults",
6831+
"effects" : {
6832+
"isAsync" : false,
6833+
"isStatic" : false,
6834+
"isThrows" : false
6835+
},
6836+
"name" : "compareAPIResults",
6837+
"parameters" : [
6838+
{
6839+
"label" : "_",
6840+
"name" : "r1",
6841+
"type" : {
6842+
"optional" : {
6843+
"_0" : {
6844+
"associatedValueEnum" : {
6845+
"_0" : "APIResult"
6846+
}
6847+
}
6848+
}
6849+
}
6850+
},
6851+
{
6852+
"label" : "_",
6853+
"name" : "r2",
6854+
"type" : {
6855+
"optional" : {
6856+
"_0" : {
6857+
"associatedValueEnum" : {
6858+
"_0" : "APIResult"
6859+
}
6860+
}
6861+
}
6862+
}
6863+
}
6864+
],
6865+
"returnType" : {
6866+
"string" : {
6867+
6868+
}
6869+
}
6870+
},
68296871
{
68306872
"abiName" : "bjs_roundTripOptionalComplexResult",
68316873
"effects" : {

Tests/prelude.mjs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,15 @@ function BridgeJSRuntimeTests_runJsWorks(instance, exports) {
571571
assert.deepEqual(exports.roundTripOptionalAPIResult(p1), p1);
572572
assert.deepEqual(exports.roundTripOptionalComplexResult(cl1), cl1);
573573

574+
const apiSuccess = { tag: exports.APIResult.Tag.Success, param0: "test success" };
575+
const apiFailure = { tag: exports.APIResult.Tag.Failure, param0: 404 };
576+
const apiInfo = { tag: exports.APIResult.Tag.Info };
577+
578+
assert.equal(exports.compareAPIResults(apiSuccess, apiFailure), "r1:success:test success,r2:failure:404");
579+
assert.equal(exports.compareAPIResults(null, apiInfo), "r1:nil,r2:info");
580+
assert.equal(exports.compareAPIResults(apiFailure, null), "r1:failure:404,r2:nil");
581+
assert.equal(exports.compareAPIResults(null, null), "r1:nil,r2:nil");
582+
574583
const optionalGreeter = new exports.Greeter("Schrödinger");
575584
const optionalGreeter2 = exports.roundTripOptionalClass(optionalGreeter);
576585
assert.equal(optionalGreeter2?.greet() ?? "", "Hello, Schrödinger!");

0 commit comments

Comments
 (0)