Skip to content

Commit f03500f

Browse files
authored
Merge pull request #585 from swiftwasm/yt/optiona-imports-fix
BridgeJS: Fix optional String return handling in generated JS glue code
2 parents 4db13d9 + b2e93d0 commit f03500f

File tree

3 files changed

+31
-56
lines changed

3 files changed

+31
-56
lines changed

Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -994,19 +994,13 @@ struct IntrinsicJSFragment: Sendable {
994994
"bjs[\"swift_js_return_optional_double\"](\(isSomeVar) ? 1 : 0, \(isSomeVar) ? \(value) : 0.0);"
995995
)
996996
case .string:
997-
let bytesVar = scope.variable("bytes")
998997
printer.write("if (\(isSomeVar)) {")
999998
printer.indent {
1000-
printer.write(
1001-
"const \(bytesVar) = \(JSGlueVariableScope.reservedTextEncoder).encode(\(value));"
1002-
)
1003-
printer.write("bjs[\"swift_js_return_optional_string\"](1, \(bytesVar), \(bytesVar).length);")
1004-
printer.write("return \(bytesVar).length;")
999+
printer.write("\(JSGlueVariableScope.reservedStorageToReturnString) = \(value);")
10051000
}
10061001
printer.write("} else {")
10071002
printer.indent {
1008-
printer.write("bjs[\"swift_js_return_optional_string\"](0, 0, 0);")
1009-
printer.write("return -1;")
1003+
printer.write("\(JSGlueVariableScope.reservedStorageToReturnString) = null;")
10101004
}
10111005
printer.write("}")
10121006
case .jsObject, .swiftProtocol:
@@ -1032,19 +1026,13 @@ struct IntrinsicJSFragment: Sendable {
10321026
case .rawValueEnum(_, let rawType):
10331027
switch rawType {
10341028
case .string:
1035-
let bytesVar = scope.variable("bytes")
10361029
printer.write("if (\(isSomeVar)) {")
10371030
printer.indent {
1038-
printer.write(
1039-
"const \(bytesVar) = \(JSGlueVariableScope.reservedTextEncoder).encode(\(value));"
1040-
)
1041-
printer.write(
1042-
"bjs[\"swift_js_return_optional_string\"](1, \(bytesVar), \(bytesVar).length);"
1043-
)
1031+
printer.write("\(JSGlueVariableScope.reservedStorageToReturnString) = \(value);")
10441032
}
10451033
printer.write("} else {")
10461034
printer.indent {
1047-
printer.write("bjs[\"swift_js_return_optional_string\"](0, 0, 0);")
1035+
printer.write("\(JSGlueVariableScope.reservedStorageToReturnString) = null;")
10481036
}
10491037
printer.write("}")
10501038
default:

Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -238,12 +238,9 @@ export async function createInstantiator(options, swift) {
238238
let ret = swift.memory.getObject(self).stringOrNull;
239239
const isSome = ret != null;
240240
if (isSome) {
241-
const bytes = textEncoder.encode(ret);
242-
bjs["swift_js_return_optional_string"](1, bytes, bytes.length);
243-
return bytes.length;
241+
tmpRetString = ret;
244242
} else {
245-
bjs["swift_js_return_optional_string"](0, 0, 0);
246-
return -1;
243+
tmpRetString = null;
247244
}
248245
} catch (error) {
249246
setException(error);
@@ -254,12 +251,9 @@ export async function createInstantiator(options, swift) {
254251
let ret = swift.memory.getObject(self).stringOrUndefined;
255252
const isSome = ret !== undefined;
256253
if (isSome) {
257-
const bytes = textEncoder.encode(ret);
258-
bjs["swift_js_return_optional_string"](1, bytes, bytes.length);
259-
return bytes.length;
254+
tmpRetString = ret;
260255
} else {
261-
bjs["swift_js_return_optional_string"](0, 0, 0);
262-
return -1;
256+
tmpRetString = null;
263257
}
264258
} catch (error) {
265259
setException(error);
@@ -395,12 +389,9 @@ export async function createInstantiator(options, swift) {
395389
let ret = swift.memory.getObject(self).roundTripStringOrNull(valueIsSome ? obj : null);
396390
const isSome = ret != null;
397391
if (isSome) {
398-
const bytes = textEncoder.encode(ret);
399-
bjs["swift_js_return_optional_string"](1, bytes, bytes.length);
400-
return bytes.length;
392+
tmpRetString = ret;
401393
} else {
402-
bjs["swift_js_return_optional_string"](0, 0, 0);
403-
return -1;
394+
tmpRetString = null;
404395
}
405396
} catch (error) {
406397
setException(error);
@@ -416,12 +407,9 @@ export async function createInstantiator(options, swift) {
416407
let ret = swift.memory.getObject(self).roundTripStringOrUndefined(valueIsSome ? obj : undefined);
417408
const isSome = ret !== undefined;
418409
if (isSome) {
419-
const bytes = textEncoder.encode(ret);
420-
bjs["swift_js_return_optional_string"](1, bytes, bytes.length);
421-
return bytes.length;
410+
tmpRetString = ret;
422411
} else {
423-
bjs["swift_js_return_optional_string"](0, 0, 0);
424-
return -1;
412+
tmpRetString = null;
425413
}
426414
} catch (error) {
427415
setException(error);

Tests/BridgeJSRuntimeTests/OptionalSupportTests.swift

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,26 +9,25 @@ final class OptionalSupportTests: XCTestCase {
99
try runJsOptionalSupportTests()
1010
}
1111

12-
// FIXME: Optional<String> return type on imported function is broken
13-
// func testRoundTripOptionalStringNull() throws {
14-
// try XCTAssertEqual(jsRoundTripOptionalStringNull("hello"), "hello")
15-
// try XCTAssertNil(jsRoundTripOptionalStringNull(nil))
16-
// }
17-
18-
// func testRoundTripOptionalStringUndefined() throws {
19-
// let some = try jsRoundTripOptionalStringUndefined(.value("hi"))
20-
// switch some {
21-
// case .value(let value):
22-
// XCTAssertEqual(value, "hi")
23-
// case .undefined:
24-
// XCTFail("Expected defined value")
25-
// }
26-
27-
// let undefined = try jsRoundTripOptionalStringUndefined(.undefinedValue)
28-
// if case .value = undefined {
29-
// XCTFail("Expected undefined")
30-
// }
31-
// }
12+
func testRoundTripOptionalStringNull() throws {
13+
try XCTAssertEqual(jsRoundTripOptionalStringNull("hello"), "hello")
14+
try XCTAssertNil(jsRoundTripOptionalStringNull(nil))
15+
}
16+
17+
func testRoundTripOptionalStringUndefined() throws {
18+
let some = try jsRoundTripOptionalStringUndefined(.value("hi"))
19+
switch some {
20+
case .value(let value):
21+
XCTAssertEqual(value, "hi")
22+
case .undefined:
23+
XCTFail("Expected defined value")
24+
}
25+
26+
let undefined = try jsRoundTripOptionalStringUndefined(.undefinedValue)
27+
if case .value = undefined {
28+
XCTFail("Expected undefined")
29+
}
30+
}
3231

3332
func testRoundTripOptionalNumberNull() throws {
3433
try XCTAssertEqual(jsRoundTripOptionalNumberNull(42), 42)

0 commit comments

Comments
 (0)