Skip to content

Commit 8716d44

Browse files
committed
BridgeJS: Remove insertion of bridging calls for aliases
1 parent 598f09b commit 8716d44

26 files changed

Lines changed: 10085 additions & 6225 deletions

Plugins/BridgeJS/Sources/BridgeJSCore/ClosureCodegen.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,9 @@ public struct ClosureCodegen {
153153
let argNames = liftInfo.parameters.map { (argName, _) in
154154
liftInfo.parameters.count > 1 ? "\(paramName)\(argName.capitalizedFirstLetter)" : paramName
155155
}
156-
let liftCall = "\(paramType.unaliased.swiftType).bridgeJSLiftParameter(\(argNames.joined(separator: ", ")))"
157-
liftedParams.append(paramType.liftAliases(expression: liftCall))
156+
liftedParams.append(
157+
"\(paramType.swiftType).bridgeJSLiftParameter(\(argNames.joined(separator: ", ")))"
158+
)
158159
}
159160

160161
let tryPrefix = signature.isThrows ? "try " : ""
@@ -198,8 +199,7 @@ public struct ClosureCodegen {
198199
}
199200
printer.write("}")
200201
default:
201-
let lowered = signature.returnType.lowerAliases(expression: "result")
202-
printer.write("return \(lowered).bridgeJSLowerReturn()")
202+
printer.write("return result.bridgeJSLowerReturn()")
203203
}
204204
}
205205
}

Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift

Lines changed: 50 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,15 @@ public class ExportSwift {
100100
}
101101
}
102102
}
103+
104+
withSpan("Render Aliases") { [self] in
105+
let aliasCodegen = AliasCodegen()
106+
for alias in skeleton.aliases {
107+
if let aliasExtension = aliasCodegen.renderAliasConformance(alias) {
108+
decls.append(aliasExtension)
109+
}
110+
}
111+
}
103112
return withSpan("Format Export Glue") {
104113
return decls.map { $0.description }.joined(separator: "\n\n")
105114
}
@@ -227,15 +236,15 @@ public class ExportSwift {
227236
} else {
228237
optionalSwiftType = "JSUndefinedOr"
229238
}
230-
typeNameForIntrinsic = "\(optionalSwiftType)<\(wrappedType.unaliased.swiftType)>"
231-
let liftCall =
232-
"\(typeNameForIntrinsic).bridgeJSLiftParameter(\(argumentsToLift.joined(separator: ", ")))"
233-
liftingExpr = "\(raw: param.type.liftAliases(expression: liftCall))"
239+
typeNameForIntrinsic = "\(optionalSwiftType)<\(wrappedType.swiftType)>"
240+
liftingExpr = ExprSyntax(
241+
"\(raw: typeNameForIntrinsic).bridgeJSLiftParameter(\(raw: argumentsToLift.joined(separator: ", ")))"
242+
)
234243
default:
235-
typeNameForIntrinsic = param.type.unaliased.swiftType
236-
let liftCall =
237-
"\(typeNameForIntrinsic).bridgeJSLiftParameter(\(argumentsToLift.joined(separator: ", ")))"
238-
liftingExpr = "\(raw: param.type.liftAliases(expression: liftCall))"
244+
typeNameForIntrinsic = param.type.swiftType
245+
liftingExpr = ExprSyntax(
246+
"\(raw: typeNameForIntrinsic).bridgeJSLiftParameter(\(raw: argumentsToLift.joined(separator: ", ")))"
247+
)
239248
}
240249

241250
liftedParameterExprs.append(liftingExpr)
@@ -280,8 +289,7 @@ public class ExportSwift {
280289
}
281290

282291
if effects.isAsync, returnType != .void {
283-
let lowered = returnType.lowerAliases(expression: callExpr.description)
284-
return CodeBlockItemSyntax(item: .init(StmtSyntax("return \(raw: lowered)")))
292+
return CodeBlockItemSyntax(item: .init(StmtSyntax("return \(raw: callExpr)")))
285293
}
286294

287295
if returnType == .void {
@@ -394,18 +402,17 @@ public class ExportSwift {
394402
return
395403
}
396404

397-
let returnAccessor = returnType.lowerAliases(expression: "ret")
398405
switch returnType {
399406
case .closure(_, useJSTypedClosure: false):
400407
append("return JSTypedClosure(ret).bridgeJSLowerReturn()")
401408
case .array, .nullable(.array, _):
402409
let stackCodegen = StackCodegen()
403-
for stmt in stackCodegen.lowerStatements(for: returnType, accessor: returnAccessor, varPrefix: "ret") {
410+
for stmt in stackCodegen.lowerStatements(for: returnType, accessor: "ret", varPrefix: "ret") {
404411
append(stmt)
405412
}
406413
case .dictionary(.swiftProtocol):
407414
let stackCodegen = StackCodegen()
408-
for stmt in stackCodegen.lowerStatements(for: returnType, accessor: returnAccessor, varPrefix: "ret") {
415+
for stmt in stackCodegen.lowerStatements(for: returnType, accessor: "ret", varPrefix: "ret") {
409416
append(stmt)
410417
}
411418
case .swiftProtocol:
@@ -421,7 +428,7 @@ public class ExportSwift {
421428
"""
422429
)
423430
default:
424-
append("return \(raw: returnAccessor).bridgeJSLowerReturn()")
431+
append("return ret.bridgeJSLowerReturn()")
425432
}
426433
}
427434

@@ -880,7 +887,7 @@ struct StackCodegen {
880887
case .string, .integer, .bool, .float, .double,
881888
.jsObject(nil), .jsValue, .swiftStruct, .swiftHeapObject, .unsafePointer,
882889
.swiftProtocol, .caseEnum, .associatedValueEnum, .rawValueEnum, .array, .dictionary, .alias:
883-
return "\(raw: type.liftAliases(expression: "\(type.unaliased.swiftType).bridgeJSStackPop()"))"
890+
return "\(raw: type.swiftType).bridgeJSStackPop()"
884891
case .jsObject(let className?):
885892
return "\(raw: className)(unsafelyWrapping: JSObject.bridgeJSStackPop())"
886893
case .nullable(let wrappedType, let kind):
@@ -898,9 +905,7 @@ struct StackCodegen {
898905
case .string, .integer, .bool, .float, .double, .jsObject(nil), .jsValue,
899906
.swiftStruct, .swiftHeapObject, .caseEnum, .associatedValueEnum, .rawValueEnum,
900907
.array, .dictionary, .alias:
901-
let popCall = "\(typeName)<\(wrappedType.unaliased.swiftType)>.bridgeJSStackPop()"
902-
let nullableType = BridgeType.nullable(wrappedType, kind)
903-
return "\(raw: nullableType.liftAliases(expression: popCall))"
908+
return "\(raw: typeName)<\(raw: wrappedType.swiftType)>.bridgeJSStackPop()"
904909
case .jsObject(let className?):
905910
return "\(raw: typeName)<JSObject>.bridgeJSStackPop().map { \(raw: className)(unsafelyWrapping: $0) }"
906911
case .nullable, .void, .namespaceEnum, .closure, .unsafePointer, .swiftProtocol:
@@ -1208,10 +1213,9 @@ struct EnumCodegen {
12081213
) {
12091214
for (index, associatedValue) in associatedValues.enumerated() {
12101215
let paramName = associatedValue.label ?? "param\(index)"
1211-
let accessor = associatedValue.type.lowerAliases(expression: paramName)
12121216
let statements = stackCodegen.lowerStatements(
12131217
for: associatedValue.type,
1214-
accessor: accessor,
1218+
accessor: paramName,
12151219
varPrefix: paramName
12161220
)
12171221
for statement in statements {
@@ -1344,10 +1348,9 @@ struct StructCodegen {
13441348
let instanceProps = structDef.properties.filter { !$0.isStatic }
13451349

13461350
for property in instanceProps {
1347-
let accessor = property.type.lowerAliases(expression: "self.\(property.name)")
13481351
let statements = stackCodegen.lowerStatements(
13491352
for: property.type,
1350-
accessor: accessor,
1353+
accessor: "self.\(property.name)",
13511354
varPrefix: property.name
13521355
)
13531356
for statement in statements {
@@ -1359,6 +1362,18 @@ struct StructCodegen {
13591362
}
13601363
}
13611364

1365+
// MARK: - AliasCodegen
1366+
1367+
struct AliasCodegen {
1368+
func renderAliasConformance(_ alias: ExportedAlias) -> DeclSyntax? {
1369+
guard let protocols = alias.underlying.aliasConformanceProtocols else {
1370+
return nil
1371+
}
1372+
let conformances = (["_BridgedSwiftAlias"] + protocols).joined(separator: ", ")
1373+
return "extension \(raw: alias.swiftCallName): \(raw: conformances) {}"
1374+
}
1375+
}
1376+
13621377
// MARK: - ProtocolCodegen
13631378

13641379
struct ProtocolCodegen {
@@ -1570,61 +1585,20 @@ extension UnsafePointerType {
15701585
}
15711586

15721587
extension BridgeType {
1573-
var unaliased: BridgeType {
1574-
switch self {
1575-
case .alias(_, let underlying): return underlying.unaliased
1576-
case .nullable(let wrapped, let kind): return .nullable(wrapped.unaliased, kind)
1577-
case .array(let element): return .array(element.unaliased)
1578-
case .dictionary(let value): return .dictionary(value.unaliased)
1579-
case .bool, .integer, .float, .double, .string, .jsValue, .jsObject,
1580-
.swiftHeapObject, .unsafePointer, .swiftProtocol, .void,
1581-
.caseEnum, .rawValueEnum, .associatedValueEnum, .swiftStruct,
1582-
.namespaceEnum, .closure:
1583-
return self
1584-
}
1585-
}
1586-
1587-
/// If this type contains an alias, convert the expression with a type of the alias to the underlying type.
1588-
func liftAliases(expression: String) -> String {
1589-
switch self {
1590-
case .alias(let name, _):
1591-
return "\(name).bridgeFromJS(\(expression))"
1592-
case .nullable(let wrapped, _):
1593-
let lifted = wrapped.liftAliases(expression: "$0")
1594-
return lifted == "$0" ? expression : "\(expression).map { \(lifted) }"
1595-
case .array(let element):
1596-
let lifted = element.liftAliases(expression: "$0")
1597-
return lifted == "$0" ? expression : "\(expression).map { \(lifted) }"
1598-
case .dictionary(let value):
1599-
let lifted = value.liftAliases(expression: "$0")
1600-
return lifted == "$0" ? expression : "\(expression).mapValues { \(lifted) }"
1601-
case .bool, .integer, .float, .double, .string, .jsValue, .jsObject,
1602-
.swiftHeapObject, .unsafePointer, .swiftProtocol, .void,
1603-
.caseEnum, .rawValueEnum, .associatedValueEnum, .swiftStruct,
1604-
.namespaceEnum, .closure:
1605-
return expression
1606-
}
1607-
}
1608-
1609-
/// Opposite of `liftAliases`: if this type contains an alias, convert the expression with a type of the underlying to the alias type.
1610-
func lowerAliases(expression: String) -> String {
1588+
var aliasConformanceProtocols: [String]? {
16111589
switch self {
1612-
case .alias:
1613-
return "\(expression).bridgeToJS()"
1614-
case .nullable(let wrapped, _):
1615-
let lowered = wrapped.lowerAliases(expression: "$0")
1616-
return lowered == "$0" ? expression : "\(expression).map { \(lowered) }"
1617-
case .array(let element):
1618-
let lowered = element.lowerAliases(expression: "$0")
1619-
return lowered == "$0" ? expression : "\(expression).map { \(lowered) }"
1620-
case .dictionary(let value):
1621-
let lowered = value.lowerAliases(expression: "$0")
1622-
return lowered == "$0" ? expression : "\(expression).mapValues { \(lowered) }"
1623-
case .bool, .integer, .float, .double, .string, .jsValue, .jsObject,
1624-
.swiftHeapObject, .unsafePointer, .swiftProtocol, .void,
1625-
.caseEnum, .rawValueEnum, .associatedValueEnum, .swiftStruct,
1626-
.namespaceEnum, .closure:
1627-
return expression
1590+
case .swiftHeapObject, .jsObject, .integer, .float, .double, .bool, .string, .jsValue:
1591+
return ["_BridgedSwiftStackType"]
1592+
case .swiftStruct:
1593+
return ["_BridgedSwiftStruct"]
1594+
case .caseEnum:
1595+
return ["_BridgedSwiftCaseEnum"]
1596+
case .associatedValueEnum:
1597+
return ["_BridgedSwiftAssociatedValueEnum"]
1598+
case .rawValueEnum, .void, .unsafePointer, .namespaceEnum,
1599+
.swiftProtocol, .closure, .nullable, .array, .dictionary, .alias:
1600+
// Not supported yet.
1601+
return nil
16281602
}
16291603
}
16301604

Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,7 @@ public struct ImportTS {
172172
if loweringInfo.useBorrowing {
173173
let returnVariableName = "ret\(borrowedArguments.count)"
174174
let assign = needsReturnVariable ? "let \(returnVariableName) = " : ""
175-
let loweredAlias = param.type.lowerAliases(expression: param.name)
176-
body.write("\(assign)\(loweredAlias).bridgeJSWithLoweredParameter { \(pattern) in")
175+
body.write("\(assign)\(param.name).bridgeJSWithLoweredParameter { \(pattern) in")
177176
body.indent()
178177
borrowedArguments.append(
179178
BorrowedArgument(
@@ -204,8 +203,7 @@ public struct ImportTS {
204203
"(\(raw: param.name) as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn()"
205204
)
206205
} else {
207-
let loweredAlias = param.type.lowerAliases(expression: param.name)
208-
initializerExpr = ExprSyntax("\(raw: loweredAlias).bridgeJSLowerParameter()")
206+
initializerExpr = ExprSyntax("\(raw: param.name).bridgeJSLowerParameter()")
209207
}
210208

211209
if loweringInfo.loweredParameters.isEmpty {
@@ -296,21 +294,18 @@ public struct ImportTS {
296294

297295
if returnType.usesSideChannelForOptionalReturn() {
298296
// Side channel returns: extern function returns Void, value is retrieved via side channel
299-
let liftCall = "\(returnType.unaliased.swiftType).bridgeJSLiftReturnFromSideChannel()"
300-
body.write("return \(returnType.liftAliases(expression: liftCall))")
297+
body.write("return \(returnType.swiftType).bridgeJSLiftReturnFromSideChannel()")
301298
} else {
302299
let liftExpr: String
303300
switch returnType {
304301
case .closure(let signature, _):
305302
liftExpr = "_BJS_Closure_\(signature.mangleName).bridgeJSLift(ret)"
306303
default:
307-
let liftCall: String
308304
if liftingInfo.valueToLift != nil {
309-
liftCall = "\(returnType.unaliased.swiftType).bridgeJSLiftReturn(ret)"
305+
liftExpr = "\(returnType.swiftType).bridgeJSLiftReturn(ret)"
310306
} else {
311-
liftCall = "\(returnType.unaliased.swiftType).bridgeJSLiftReturn()"
307+
liftExpr = "\(returnType.swiftType).bridgeJSLiftReturn()"
312308
}
313-
liftExpr = returnType.liftAliases(expression: liftCall)
314309
}
315310
body.write("return \(liftExpr)")
316311
}
@@ -908,7 +903,7 @@ extension BridgeType {
908903
}
909904

910905
func loweringParameterInfo(context: BridgeContext = .importTS) throws -> LoweringParameterInfo {
911-
switch self {
906+
switch self.unaliased {
912907
case .bool: return .bool
913908
case .integer(let t): return LoweringParameterInfo(loweredParameters: [("value", t.wasmCoreType)])
914909
case .float: return .float
@@ -962,8 +957,8 @@ extension BridgeType {
962957
return LoweringParameterInfo(loweredParameters: params, useBorrowing: wrappedInfo.useBorrowing)
963958
case .array, .dictionary:
964959
return LoweringParameterInfo(loweredParameters: [])
965-
case .alias(_, let underlying):
966-
return try underlying.loweringParameterInfo(context: context)
960+
case .alias:
961+
preconditionFailure()
967962
}
968963
}
969964

@@ -983,7 +978,7 @@ extension BridgeType {
983978
func liftingReturnInfo(
984979
context: BridgeContext = .importTS
985980
) throws -> LiftingReturnInfo {
986-
switch self {
981+
switch self.unaliased {
987982
case .bool: return .bool
988983
case .integer(let t): return LiftingReturnInfo(valueToLift: t.wasmCoreType)
989984
case .float: return .float
@@ -1026,7 +1021,7 @@ extension BridgeType {
10261021
case .nullable(let wrappedType, _):
10271022
// jsObject and `@JS struct` use the stack ABI for optionals — the thunk returns
10281023
// void and the value (plus isSome discriminator) flows through the stacks.
1029-
if case .jsObject = wrappedType.unaliased {
1024+
if case .jsObject = wrappedType {
10301025
return LiftingReturnInfo(valueToLift: nil)
10311026
}
10321027
if case .swiftStruct = wrappedType, context == .importTS {
@@ -1036,8 +1031,8 @@ extension BridgeType {
10361031
return LiftingReturnInfo(valueToLift: wrappedInfo.valueToLift)
10371032
case .array, .dictionary:
10381033
return LiftingReturnInfo(valueToLift: nil)
1039-
case .alias(_, let underlying):
1040-
return try underlying.liftingReturnInfo(context: context)
1034+
case .alias:
1035+
preconditionFailure()
10411036
}
10421037
}
10431038
}

Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -552,10 +552,7 @@ public final class SwiftToSkeleton {
552552
swiftCallName: String,
553553
errors: inout [DiagnosticError]
554554
) -> BridgeType? {
555-
if let targetDecl = typeDeclResolver.resolve(aliasTarget),
556-
let targetJSAttribute = targetDecl.attributes.firstJSAttribute,
557-
extractAliasTarget(from: targetJSAttribute) != nil
558-
{
555+
func diagnoseChainedAlias() -> BridgeType? {
559556
errors.append(
560557
DiagnosticError(
561558
node: aliasTarget,
@@ -565,7 +562,17 @@ public final class SwiftToSkeleton {
565562
)
566563
return nil
567564
}
565+
if let targetDecl = typeDeclResolver.resolve(aliasTarget),
566+
let targetJSAttribute = targetDecl.attributes.firstJSAttribute,
567+
extractAliasTarget(from: targetJSAttribute) != nil
568+
{
569+
return diagnoseChainedAlias()
570+
}
568571
guard let targetType = lookupType(for: aliasTarget, errors: &errors) else { return nil }
572+
if case .alias = targetType {
573+
// Alias declared in another module.
574+
return diagnoseChainedAlias()
575+
}
569576
if case .swiftProtocol = targetType {
570577
errors.append(
571578
DiagnosticError(
@@ -1697,6 +1704,15 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor {
16971704
errors.append(contentsOf: lookupErrors)
16981705
return
16991706
}
1707+
guard underlying.aliasConformanceProtocols != nil else {
1708+
errors.append(
1709+
DiagnosticError(
1710+
node: aliasTarget,
1711+
message: "Representation \(underlying.swiftType) is not supported"
1712+
)
1713+
)
1714+
return
1715+
}
17001716
exportedAliases.append(
17011717
ExportedAlias(swiftCallName: swiftCallName, underlying: underlying)
17021718
)

0 commit comments

Comments
 (0)