diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift index fb9cee01c..fb81d9089 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift @@ -818,7 +818,7 @@ public final class SwiftToSkeleton { while let parent = currentNode { if let extensionDecl = parent.as(ExtensionDeclSyntax.self) { - if let extendedDecl = typeDeclResolver.resolve(extensionDecl.extendedType), + if let extendedDecl = typeDeclResolver.resolveExtensionTarget(extensionDecl.extendedType), visitedExtendedTypes.insert(extendedDecl.id).inserted { declarations.append(Syntax(extendedDecl)) @@ -1996,7 +1996,7 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { /// Walks extension members under the matching type’s state, returning whether the type was found. func resolveExtension(_ ext: ExtensionDeclSyntax) -> Bool { - guard let extendedDecl = parent.typeDeclResolver.resolve(ext.extendedType) else { + guard let extendedDecl = parent.typeDeclResolver.resolveExtensionTarget(ext.extendedType) else { return false } let swiftCallName = parent.computeSwiftCallName(for: extendedDecl, itemName: extendedDecl.name.text) diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/TypeDeclResolver.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/TypeDeclResolver.swift index e5d77939b..4df546b8a 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/TypeDeclResolver.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/TypeDeclResolver.swift @@ -92,7 +92,7 @@ class TypeDeclResolver { } /// Builds the type name scope for a given type usage - private func buildScope(type: IdentifierTypeSyntax) -> QualifiedName { + private func buildScope(type: TypeSyntax) -> QualifiedName { var innerToOuter: [String] = [] var context: SyntaxProtocol = type while let parent = context.parent { @@ -108,25 +108,29 @@ class TypeDeclResolver { return innerToOuter.reversed() } - /// Looks up a qualified name of a type declaration by its unqualified type usage + /// Looks up a qualified name of a type declaration relative to its lexical scope /// Returns the qualified name hierarchy of the type declaration - /// If the type declaration is not found, returns the unqualified name - private func tryQualify(type: IdentifierTypeSyntax) -> QualifiedName { - let name = type.name.text + /// If the type declaration is not found, returns the original qualified name + private func tryQualify(type: TypeSyntax) -> QualifiedName? { + guard let components = type.qualifiedComponents else { + return nil + } let scope = buildScope(type: type) /// Search for the type declaration from the innermost scope to the outermost scope for i in (0...scope.count).reversed() { - let qualifiedName = Array(scope[0.. TypeDecl? { - let qualifiedName = tryQualify(type: type) + guard let qualifiedName = tryQualify(type: TypeSyntax(type)) else { + return nil + } return typeDeclByQualifiedName[qualifiedName] } @@ -139,36 +143,35 @@ class TypeDeclResolver { /// /// Supported inputs: /// - IdentifierTypeSyntax (e.g. `Method`) — resolved relative to the lexical scope, preferring the innermost enclosing type. - /// - MemberTypeSyntax (e.g. `Networking.API.Method`) — resolved by recursively building the fully qualified name. + /// - MemberTypeSyntax (e.g. `Networking.API.Method`) — resolved relative to the lexical scope before falling back to the fully qualified name. /// /// Resolution strategy: - /// 1. If the node is IdentifierTypeSyntax, call `lookupType(for:)` which attempts scope-aware qualification via `tryQualify`. - /// 2. Otherwise, attempt to build a fully qualified name with `qualifiedComponents` and look it up with `lookupType(fullyQualified:)`. + /// Build the qualified name with `qualifiedComponents`, then attempt scope-aware qualification via `tryQualify`. /// /// - Parameter type: The SwiftSyntax node representing a type appearance in source code. /// - Returns: The nominal declaration (enum/class/actor/struct) if found, otherwise nil. func resolve(_ type: TypeSyntax) -> TypeDecl? { - if let id = type.as(IdentifierTypeSyntax.self) { - return lookupType(for: id) - } - if let components = type.qualifiedComponents { - return lookupType(fullyQualified: components) + if let qualifiedName = tryQualify(type: type) { + return lookupType(fullyQualified: qualifiedName) } return nil } + func resolveExtensionTarget(_ type: TypeSyntax) -> TypeDecl? { + guard let qualifiedName = type.qualifiedComponents else { + return nil + } + return lookupType(fullyQualified: qualifiedName) + } + /// Resolves a type usage node to a type alias declaration /// /// - Parameter type: The SwiftSyntax node representing a type appearance in source code. /// - Returns: The type alias declaration if found, otherwise nil. func resolveTypeAlias(_ type: TypeSyntax) -> TypeAliasDeclSyntax? { - if let id = type.as(IdentifierTypeSyntax.self) { - let qualifiedName = tryQualify(type: id) + if let qualifiedName = tryQualify(type: type) { return typeAliasByQualifiedName[qualifiedName] } - if let components = type.qualifiedComponents { - return typeAliasByQualifiedName[components] - } return nil } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/RelativeQualifiedTypes.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/RelativeQualifiedTypes.swift new file mode 100644 index 000000000..b1eae64dd --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/RelativeQualifiedTypes.swift @@ -0,0 +1,37 @@ +@JS class Library { + @JS struct Shelf { + @JS struct Divider { + var slot: Int + + @JS init(slot: Int) { + self.slot = slot + } + } + } + + @JS init() {} +} + +extension Library { + @JS func divider(_ value: Shelf.Divider) -> Shelf.Divider { + value + } +} + +@JS class Outer { + @JS struct Inner { + @JS struct Outer { + @JS struct Inner { + @JS init() {} + } + } + + @JS init() {} + } + + @JS init() {} +} + +extension Outer.Inner { + @JS func marker() -> Int { 1 } +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/RelativeQualifiedTypes.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/RelativeQualifiedTypes.json new file mode 100644 index 000000000..0872c6d79 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/RelativeQualifiedTypes.json @@ -0,0 +1,239 @@ +{ + "exported" : { + "aliases" : [ + + ], + "classes" : [ + { + "constructor" : { + "abiName" : "bjs_Library_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + + ] + }, + "methods" : [ + { + "abiName" : "bjs_Library_divider", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "divider", + "parameters" : [ + { + "label" : "_", + "name" : "value", + "type" : { + "swiftStruct" : { + "_0" : "Library.Shelf.Divider" + } + } + } + ], + "returnType" : { + "swiftStruct" : { + "_0" : "Library.Shelf.Divider" + } + } + } + ], + "name" : "Library", + "properties" : [ + + ], + "swiftCallName" : "Library" + }, + { + "constructor" : { + "abiName" : "bjs_Outer_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + + ] + }, + "methods" : [ + + ], + "name" : "Outer", + "properties" : [ + + ], + "swiftCallName" : "Outer" + } + ], + "enums" : [ + + ], + "exposeToGlobal" : false, + "functions" : [ + + ], + "protocols" : [ + + ], + "structs" : [ + { + "methods" : [ + + ], + "name" : "Shelf", + "namespace" : [ + "Library" + ], + "properties" : [ + + ], + "swiftCallName" : "Library.Shelf" + }, + { + "constructor" : { + "abiName" : "bjs_Library_Shelf_Divider_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + { + "label" : "slot", + "name" : "slot", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ] + }, + "methods" : [ + + ], + "name" : "Divider", + "namespace" : [ + "Library", + "Shelf" + ], + "properties" : [ + { + "isReadonly" : true, + "isStatic" : false, + "name" : "slot", + "namespace" : [ + "Library", + "Shelf" + ], + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "swiftCallName" : "Library.Shelf.Divider" + }, + { + "constructor" : { + "abiName" : "bjs_Outer_Inner_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + + ] + }, + "methods" : [ + { + "abiName" : "bjs_Outer_Inner_marker", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "marker", + "parameters" : [ + + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "name" : "Inner", + "namespace" : [ + "Outer" + ], + "properties" : [ + + ], + "swiftCallName" : "Outer.Inner" + }, + { + "methods" : [ + + ], + "name" : "Outer", + "namespace" : [ + "Outer", + "Inner" + ], + "properties" : [ + + ], + "swiftCallName" : "Outer.Inner.Outer" + }, + { + "constructor" : { + "abiName" : "bjs_Outer_Inner_Outer_Inner_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + + ] + }, + "methods" : [ + + ], + "name" : "Inner", + "namespace" : [ + "Outer", + "Inner", + "Outer" + ], + "properties" : [ + + ], + "swiftCallName" : "Outer.Inner.Outer.Inner" + } + ] + }, + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/RelativeQualifiedTypes.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/RelativeQualifiedTypes.swift new file mode 100644 index 000000000..0a6b272e9 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/RelativeQualifiedTypes.swift @@ -0,0 +1,399 @@ +extension Library.Shelf: _BridgedSwiftStruct { + @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> Library.Shelf { + return Library.Shelf() + } + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() { + } + + init(unsafelyCopying jsObject: JSObject) { + _bjs_struct_lower_Library_Shelf(jsObject.bridgeJSLowerParameter()) + self = Self.bridgeJSStackPop() + } + + func toJSObject() -> JSObject { + let __bjs_self = self + __bjs_self.bridgeJSStackPush() + return JSObject(id: UInt32(bitPattern: _bjs_struct_lift_Library_Shelf())) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lower_Library_Shelf") +fileprivate func _bjs_struct_lower_Library_Shelf_extern(_ objectId: Int32) -> Void +#else +fileprivate func _bjs_struct_lower_Library_Shelf_extern(_ objectId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lower_Library_Shelf(_ objectId: Int32) -> Void { + return _bjs_struct_lower_Library_Shelf_extern(objectId) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lift_Library_Shelf") +fileprivate func _bjs_struct_lift_Library_Shelf_extern() -> Int32 +#else +fileprivate func _bjs_struct_lift_Library_Shelf_extern() -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lift_Library_Shelf() -> Int32 { + return _bjs_struct_lift_Library_Shelf_extern() +} + +extension Library.Shelf.Divider: _BridgedSwiftStruct { + @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> Library.Shelf.Divider { + let slot = Int.bridgeJSStackPop() + return Library.Shelf.Divider(slot: slot) + } + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() { + self.slot.bridgeJSStackPush() + } + + init(unsafelyCopying jsObject: JSObject) { + _bjs_struct_lower_Library_Shelf_Divider(jsObject.bridgeJSLowerParameter()) + self = Self.bridgeJSStackPop() + } + + func toJSObject() -> JSObject { + let __bjs_self = self + __bjs_self.bridgeJSStackPush() + return JSObject(id: UInt32(bitPattern: _bjs_struct_lift_Library_Shelf_Divider())) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lower_Library_Shelf_Divider") +fileprivate func _bjs_struct_lower_Library_Shelf_Divider_extern(_ objectId: Int32) -> Void +#else +fileprivate func _bjs_struct_lower_Library_Shelf_Divider_extern(_ objectId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lower_Library_Shelf_Divider(_ objectId: Int32) -> Void { + return _bjs_struct_lower_Library_Shelf_Divider_extern(objectId) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lift_Library_Shelf_Divider") +fileprivate func _bjs_struct_lift_Library_Shelf_Divider_extern() -> Int32 +#else +fileprivate func _bjs_struct_lift_Library_Shelf_Divider_extern() -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lift_Library_Shelf_Divider() -> Int32 { + return _bjs_struct_lift_Library_Shelf_Divider_extern() +} + +@_expose(wasm, "bjs_Library_Shelf_Divider_init") +@_cdecl("bjs_Library_Shelf_Divider_init") +public func _bjs_Library_Shelf_Divider_init(_ slot: Int32) -> Void { + #if arch(wasm32) + let ret = Library.Shelf.Divider(slot: Int.bridgeJSLiftParameter(slot)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +extension Outer.Inner: _BridgedSwiftStruct { + @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> Outer.Inner { + return Outer.Inner() + } + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() { + } + + init(unsafelyCopying jsObject: JSObject) { + _bjs_struct_lower_Outer_Inner(jsObject.bridgeJSLowerParameter()) + self = Self.bridgeJSStackPop() + } + + func toJSObject() -> JSObject { + let __bjs_self = self + __bjs_self.bridgeJSStackPush() + return JSObject(id: UInt32(bitPattern: _bjs_struct_lift_Outer_Inner())) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lower_Outer_Inner") +fileprivate func _bjs_struct_lower_Outer_Inner_extern(_ objectId: Int32) -> Void +#else +fileprivate func _bjs_struct_lower_Outer_Inner_extern(_ objectId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lower_Outer_Inner(_ objectId: Int32) -> Void { + return _bjs_struct_lower_Outer_Inner_extern(objectId) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lift_Outer_Inner") +fileprivate func _bjs_struct_lift_Outer_Inner_extern() -> Int32 +#else +fileprivate func _bjs_struct_lift_Outer_Inner_extern() -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lift_Outer_Inner() -> Int32 { + return _bjs_struct_lift_Outer_Inner_extern() +} + +@_expose(wasm, "bjs_Outer_Inner_init") +@_cdecl("bjs_Outer_Inner_init") +public func _bjs_Outer_Inner_init() -> Void { + #if arch(wasm32) + let ret = Outer.Inner() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Outer_Inner_marker") +@_cdecl("bjs_Outer_Inner_marker") +public func _bjs_Outer_Inner_marker() -> Int32 { + #if arch(wasm32) + let ret = Outer.Inner.bridgeJSLiftParameter().marker() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +extension Outer.Inner.Outer: _BridgedSwiftStruct { + @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> Outer.Inner.Outer { + return Outer.Inner.Outer() + } + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() { + } + + init(unsafelyCopying jsObject: JSObject) { + _bjs_struct_lower_Outer_Inner_Outer(jsObject.bridgeJSLowerParameter()) + self = Self.bridgeJSStackPop() + } + + func toJSObject() -> JSObject { + let __bjs_self = self + __bjs_self.bridgeJSStackPush() + return JSObject(id: UInt32(bitPattern: _bjs_struct_lift_Outer_Inner_Outer())) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lower_Outer_Inner_Outer") +fileprivate func _bjs_struct_lower_Outer_Inner_Outer_extern(_ objectId: Int32) -> Void +#else +fileprivate func _bjs_struct_lower_Outer_Inner_Outer_extern(_ objectId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lower_Outer_Inner_Outer(_ objectId: Int32) -> Void { + return _bjs_struct_lower_Outer_Inner_Outer_extern(objectId) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lift_Outer_Inner_Outer") +fileprivate func _bjs_struct_lift_Outer_Inner_Outer_extern() -> Int32 +#else +fileprivate func _bjs_struct_lift_Outer_Inner_Outer_extern() -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lift_Outer_Inner_Outer() -> Int32 { + return _bjs_struct_lift_Outer_Inner_Outer_extern() +} + +extension Outer.Inner.Outer.Inner: _BridgedSwiftStruct { + @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> Outer.Inner.Outer.Inner { + return Outer.Inner.Outer.Inner() + } + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() { + } + + init(unsafelyCopying jsObject: JSObject) { + _bjs_struct_lower_Outer_Inner_Outer_Inner(jsObject.bridgeJSLowerParameter()) + self = Self.bridgeJSStackPop() + } + + func toJSObject() -> JSObject { + let __bjs_self = self + __bjs_self.bridgeJSStackPush() + return JSObject(id: UInt32(bitPattern: _bjs_struct_lift_Outer_Inner_Outer_Inner())) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lower_Outer_Inner_Outer_Inner") +fileprivate func _bjs_struct_lower_Outer_Inner_Outer_Inner_extern(_ objectId: Int32) -> Void +#else +fileprivate func _bjs_struct_lower_Outer_Inner_Outer_Inner_extern(_ objectId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lower_Outer_Inner_Outer_Inner(_ objectId: Int32) -> Void { + return _bjs_struct_lower_Outer_Inner_Outer_Inner_extern(objectId) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lift_Outer_Inner_Outer_Inner") +fileprivate func _bjs_struct_lift_Outer_Inner_Outer_Inner_extern() -> Int32 +#else +fileprivate func _bjs_struct_lift_Outer_Inner_Outer_Inner_extern() -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lift_Outer_Inner_Outer_Inner() -> Int32 { + return _bjs_struct_lift_Outer_Inner_Outer_Inner_extern() +} + +@_expose(wasm, "bjs_Outer_Inner_Outer_Inner_init") +@_cdecl("bjs_Outer_Inner_Outer_Inner_init") +public func _bjs_Outer_Inner_Outer_Inner_init() -> Void { + #if arch(wasm32) + let ret = Outer.Inner.Outer.Inner() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Library_init") +@_cdecl("bjs_Library_init") +public func _bjs_Library_init() -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = Library() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Library_divider") +@_cdecl("bjs_Library_divider") +public func _bjs_Library_divider(_ _self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = Library.bridgeJSLiftParameter(_self).divider(_: Library.Shelf.Divider.bridgeJSLiftParameter()) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Library_deinit") +@_cdecl("bjs_Library_deinit") +public func _bjs_Library_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + Unmanaged.fromOpaque(pointer).release() + #else + fatalError("Only available on WebAssembly") + #endif +} + +extension Library: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { + var jsValue: JSValue { + return .object(JSObject(id: UInt32(bitPattern: _bjs_Library_wrap(Unmanaged.passRetained(self).toOpaque())))) + } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_Library_wrap(Unmanaged.passRetained(self).toOpaque()) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_Library_wrap") +fileprivate func _bjs_Library_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 +#else +fileprivate func _bjs_Library_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_Library_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { + return _bjs_Library_wrap_extern(pointer) +} + +@_expose(wasm, "bjs_Outer_init") +@_cdecl("bjs_Outer_init") +public func _bjs_Outer_init() -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = Outer() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Outer_deinit") +@_cdecl("bjs_Outer_deinit") +public func _bjs_Outer_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + Unmanaged.fromOpaque(pointer).release() + #else + fatalError("Only available on WebAssembly") + #endif +} + +extension Outer: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { + var jsValue: JSValue { + return .object(JSObject(id: UInt32(bitPattern: _bjs_Outer_wrap(Unmanaged.passRetained(self).toOpaque())))) + } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_Outer_wrap(Unmanaged.passRetained(self).toOpaque()) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_Outer_wrap") +fileprivate func _bjs_Outer_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 +#else +fileprivate func _bjs_Outer_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_Outer_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { + return _bjs_Outer_wrap_extern(pointer) +} + +extension Library.Shelf: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Library.Shelf.bridgeJSMakeTypeHandle() +} + +extension Library.Shelf.Divider: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Library.Shelf.Divider.bridgeJSMakeTypeHandle() +} + +extension Outer.Inner: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Outer.Inner.bridgeJSMakeTypeHandle() +} + +extension Outer.Inner.Outer: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Outer.Inner.Outer.bridgeJSMakeTypeHandle() +} + +extension Outer.Inner.Outer.Inner: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Outer.Inner.Outer.Inner.bridgeJSMakeTypeHandle() +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Library.Shelf.bridgeJSTypeID, + Library.Shelf.Divider.bridgeJSTypeID, + Outer.Inner.bridgeJSTypeID, + Outer.Inner.Outer.bridgeJSTypeID, + Outer.Inner.Outer.Inner.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/RelativeQualifiedTypes.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/RelativeQualifiedTypes.d.ts new file mode 100644 index 000000000..1297973a9 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/RelativeQualifiedTypes.d.ts @@ -0,0 +1,70 @@ +// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, +// DO NOT EDIT. +// +// To update this file, just rebuild your project or run +// `swift package bridge-js`. + +export namespace Library { + export interface Shelf { + } + export namespace Shelf { + export interface Divider { + slot: number; + } + } +} +export namespace Outer { + export interface Inner { + marker(): number; + } + export namespace Inner { + export interface Outer { + } + export namespace Outer { + export interface Inner { + } + } + } +} +/// Represents a Swift heap object like a class instance or an actor instance. +export interface SwiftHeapObject { + /// Release the heap object. + /// + /// Note: Calling this method will release the heap object and it will no longer be accessible. + release(): void; +} +export interface Library extends SwiftHeapObject { + divider(value: Library.Shelf.Divider): Library.Shelf.Divider; +} +export interface Outer extends SwiftHeapObject { +} +export type Exports = { + Library: { + new(): Library; + Shelf: { + Divider: { + init(slot: number): Library.Shelf.Divider; + }, + }, + }, + Outer: { + new(): Outer; + Inner: { + init(): Outer.Inner; + Outer: { + Inner: { + init(): Outer.Inner.Outer.Inner; + }, + }, + }, + }, +} +export type Imports = { +} +export function createInstantiator(options: { + imports: Imports; +}, swift: any): Promise<{ + addImports: (importObject: WebAssembly.Imports) => void; + setInstance: (instance: WebAssembly.Instance) => void; + createExports: (instance: WebAssembly.Instance) => Exports; +}>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/RelativeQualifiedTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/RelativeQualifiedTypes.js new file mode 100644 index 000000000..2765d709f --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/RelativeQualifiedTypes.js @@ -0,0 +1,440 @@ +// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, +// DO NOT EDIT. +// +// To update this file, just rebuild your project or run +// `swift package bridge-js`. + +export async function createInstantiator(options, swift) { + let instance; + let memory; + let setException; + let decodeString; + const textDecoder = new TextDecoder("utf-8"); + const textEncoder = new TextEncoder("utf-8"); + let tmpRetString; + let tmpRetBytes; + let tmpRetException; + let tmpRetOptionalBool; + let tmpRetOptionalInt; + let tmpRetOptionalFloat; + let tmpRetOptionalDouble; + let tmpRetOptionalHeapObject; + let strStack = []; + let i32Stack = []; + let i64Stack = []; + let f32Stack = []; + let f64Stack = []; + let ptrStack = []; + let taStack = []; + const enumHelpers = {}; + const structHelpers = {}; + + let _exports = null; + let bjs = null; + const __bjs_createStructHelpers_M10TestModuleT7LibraryT5Shelf = () => ({ + lower: (value) => { + }, + lift: () => { + return { }; + } + }); + const __bjs_createStructHelpers_M10TestModuleT7LibraryT5ShelfT7Divider = () => ({ + lower: (value) => { + i32Stack.push((value.slot | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return { slot: int }; + } + }); + const __bjs_createStructHelpers_M10TestModuleT5OuterT5Inner = () => ({ + lower: (value) => { + }, + lift: () => { + const instance1 = { }; + instance1.marker = function() { + structHelpers.M10TestModuleT5OuterT5Inner.lower(this); + const ret = instance.exports.bjs_Outer_Inner_marker(); + return ret; + }.bind(instance1); + return instance1; + } + }); + const __bjs_createStructHelpers_M10TestModuleT5OuterT5InnerT5Outer = () => ({ + lower: (value) => { + }, + lift: () => { + return { }; + } + }); + const __bjs_createStructHelpers_M10TestModuleT5OuterT5InnerT5OuterT5Inner = () => ({ + lower: (value) => { + }, + lift: () => { + return { }; + } + }); + + return { + /** + * @param {WebAssembly.Imports} importObject + */ + addImports: (importObject, importsContext) => { + bjs = {}; + importObject["bjs"] = bjs; + bjs["swift_js_return_string"] = function(ptr, len) { + tmpRetString = decodeString(ptr, len); + } + bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { + const source = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const bytes = new Uint8Array(memory.buffer, bytesPtr >>> 0); + bytes.set(source); + } + bjs["swift_js_make_js_string"] = function(ptr, len) { + return swift.memory.retain(decodeString(ptr, len)); + } + bjs["swift_js_init_memory_with_result"] = function(ptr, len) { + const target = new Uint8Array(memory.buffer, ptr >>> 0, len >>> 0); + target.set(tmpRetBytes); + tmpRetBytes = undefined; + } + bjs["swift_js_throw"] = function(id) { + tmpRetException = swift.memory.retainByRef(id); + } + bjs["swift_js_retain"] = function(id) { + return swift.memory.retainByRef(id); + } + bjs["swift_js_release"] = function(id) { + swift.memory.release(id); + } + bjs["swift_js_push_i32"] = function(v) { + i32Stack.push(v | 0); + } + bjs["swift_js_push_f32"] = function(v) { + f32Stack.push(Math.fround(v)); + } + bjs["swift_js_push_f64"] = function(v) { + f64Stack.push(v); + } + bjs["swift_js_push_string"] = function(ptr, len) { + const value = decodeString(ptr, len); + strStack.push(value); + } + bjs["swift_js_pop_i32"] = function() { + return i32Stack.pop(); + } + bjs["swift_js_pop_f32"] = function() { + return f32Stack.pop(); + } + bjs["swift_js_pop_f64"] = function() { + return f64Stack.pop(); + } + bjs["swift_js_push_pointer"] = function(pointer) { + ptrStack.push(pointer); + } + bjs["swift_js_pop_pointer"] = function() { + return ptrStack.pop(); + } + bjs["swift_js_push_i64"] = function(v) { + i64Stack.push(v); + } + bjs["swift_js_pop_i64"] = function() { + return i64Stack.pop(); + } + const taCtors = [Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array]; + bjs["swift_js_push_typed_array"] = function(kind, ptr, count) { + const Ctor = taCtors[kind]; + const byteLen = count * Ctor.BYTES_PER_ELEMENT; + const copy = memory.buffer.slice(ptr, ptr + byteLen); + taStack.push(Array.from(new Ctor(copy))); + } + bjs["swift_js_struct_lower_Library_Shelf"] = function(objectId) { + structHelpers.M10TestModuleT7LibraryT5Shelf.lower(swift.memory.getObject(objectId)); + } + bjs["swift_js_struct_lift_Library_Shelf"] = function() { + const value = structHelpers.M10TestModuleT7LibraryT5Shelf.lift(); + return swift.memory.retain(value); + } + bjs["swift_js_struct_lower_Library_Shelf_Divider"] = function(objectId) { + structHelpers.M10TestModuleT7LibraryT5ShelfT7Divider.lower(swift.memory.getObject(objectId)); + } + bjs["swift_js_struct_lift_Library_Shelf_Divider"] = function() { + const value = structHelpers.M10TestModuleT7LibraryT5ShelfT7Divider.lift(); + return swift.memory.retain(value); + } + bjs["swift_js_struct_lower_Outer_Inner"] = function(objectId) { + structHelpers.M10TestModuleT5OuterT5Inner.lower(swift.memory.getObject(objectId)); + } + bjs["swift_js_struct_lift_Outer_Inner"] = function() { + const value = structHelpers.M10TestModuleT5OuterT5Inner.lift(); + return swift.memory.retain(value); + } + bjs["swift_js_struct_lower_Outer_Inner_Outer"] = function(objectId) { + structHelpers.M10TestModuleT5OuterT5InnerT5Outer.lower(swift.memory.getObject(objectId)); + } + bjs["swift_js_struct_lift_Outer_Inner_Outer"] = function() { + const value = structHelpers.M10TestModuleT5OuterT5InnerT5Outer.lift(); + return swift.memory.retain(value); + } + bjs["swift_js_struct_lower_Outer_Inner_Outer_Inner"] = function(objectId) { + structHelpers.M10TestModuleT5OuterT5InnerT5OuterT5Inner.lower(swift.memory.getObject(objectId)); + } + bjs["swift_js_struct_lift_Outer_Inner_Outer_Inner"] = function() { + const value = structHelpers.M10TestModuleT5OuterT5InnerT5OuterT5Inner.lift(); + return swift.memory.retain(value); + } + bjs["bjs_core_register_type_handles"] = function() {}; + bjs["bjs_TestModule_register_type_handles"] = function() {}; + const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); + bjs["swift_js_make_promise"] = function() { + let resolve, reject; + const promise = new Promise((res, rej) => { resolve = res; reject = rej; }); + promise[__bjs_promiseSettlers] = { resolve, reject }; + return swift.memory.retain(promise); + } + bjs["swift_js_return_optional_bool"] = function(isSome, value) { + if (isSome === 0) { + tmpRetOptionalBool = null; + } else { + tmpRetOptionalBool = value !== 0; + } + } + bjs["swift_js_return_optional_int"] = function(isSome, value) { + if (isSome === 0) { + tmpRetOptionalInt = null; + } else { + tmpRetOptionalInt = value | 0; + } + } + bjs["swift_js_return_optional_float"] = function(isSome, value) { + if (isSome === 0) { + tmpRetOptionalFloat = null; + } else { + tmpRetOptionalFloat = Math.fround(value); + } + } + bjs["swift_js_return_optional_double"] = function(isSome, value) { + if (isSome === 0) { + tmpRetOptionalDouble = null; + } else { + tmpRetOptionalDouble = value; + } + } + bjs["swift_js_return_optional_string"] = function(isSome, ptr, len) { + if (isSome === 0) { + tmpRetString = null; + } else { + tmpRetString = decodeString(ptr, len); + } + } + bjs["swift_js_return_optional_object"] = function(isSome, objectId) { + if (isSome === 0) { + tmpRetString = null; + } else { + tmpRetString = swift.memory.getObject(objectId); + } + } + bjs["swift_js_return_optional_heap_object"] = function(isSome, pointer) { + if (isSome === 0) { + tmpRetOptionalHeapObject = null; + } else { + tmpRetOptionalHeapObject = pointer; + } + } + bjs["swift_js_get_optional_int_presence"] = function() { + return tmpRetOptionalInt != null ? 1 : 0; + } + bjs["swift_js_get_optional_int_value"] = function() { + const value = tmpRetOptionalInt; + tmpRetOptionalInt = undefined; + return value; + } + bjs["swift_js_get_optional_string"] = function() { + const str = tmpRetString; + tmpRetString = undefined; + if (str == null) { + return -1; + } else { + const bytes = textEncoder.encode(str); + tmpRetBytes = bytes; + return bytes.length; + } + } + bjs["swift_js_get_optional_float_presence"] = function() { + return tmpRetOptionalFloat != null ? 1 : 0; + } + bjs["swift_js_get_optional_float_value"] = function() { + const value = tmpRetOptionalFloat; + tmpRetOptionalFloat = undefined; + return value; + } + bjs["swift_js_get_optional_double_presence"] = function() { + return tmpRetOptionalDouble != null ? 1 : 0; + } + bjs["swift_js_get_optional_double_value"] = function() { + const value = tmpRetOptionalDouble; + tmpRetOptionalDouble = undefined; + return value; + } + bjs["swift_js_get_optional_heap_object_pointer"] = function() { + const pointer = tmpRetOptionalHeapObject; + tmpRetOptionalHeapObject = undefined; + return pointer || 0; + } + bjs["swift_js_closure_unregister"] = function(funcRef) {} + // Wrapper functions for module: TestModule + if (!importObject["TestModule"]) { + importObject["TestModule"] = {}; + } + importObject["TestModule"]["bjs_Library_wrap"] = function(pointer) { + const obj = _exports['Library'].__construct(pointer); + return swift.memory.retain(obj); + }; + importObject["TestModule"]["bjs_Outer_wrap"] = function(pointer) { + const obj = _exports['Outer'].__construct(pointer); + return swift.memory.retain(obj); + }; + }, + setInstance: (i) => { + instance = i; + memory = instance.exports.memory; + + decodeString = (ptr, len) => { const bytes = new Uint8Array(memory.buffer, ptr >>> 0, len >>> 0); return textDecoder.decode(bytes); } + + setException = (error) => { + instance.exports._swift_js_exception.value = swift.memory.retain(error) + } + }, + /** @param {WebAssembly.Instance} instance */ + createExports: (instance) => { + const js = swift.memory.heap; + const swiftHeapObjectFinalizationRegistry = (typeof FinalizationRegistry === "undefined") ? { register: () => {}, unregister: () => {} } : new FinalizationRegistry((state) => { + if (state.hasReleased) { + return; + } + state.hasReleased = true; + state.identityMap?.delete(state.pointer); + state.deinit(state.pointer); + }); + + /// Represents a Swift heap object like a class instance or an actor instance. + class SwiftHeapObject { + static __wrap(pointer, deinit, prototype, identityCache) { + pointer = pointer >>> 0; + const makeFresh = (identityMap) => { + const obj = Object.create(prototype); + const state = { pointer, deinit, hasReleased: false, identityMap }; + obj.pointer = pointer; + obj.__swiftHeapObjectState = state; + swiftHeapObjectFinalizationRegistry.register(obj, state, state); + if (identityMap) { + identityMap.set(pointer, new WeakRef(obj)); + } + return obj; + }; + + if (!identityCache) { + return makeFresh(null); + } + + const cached = identityCache.get(pointer)?.deref(); + if (cached && !cached.__swiftHeapObjectState.hasReleased) { + deinit(pointer); + return cached; + } + if (identityCache.has(pointer)) { + identityCache.delete(pointer); + } + + return makeFresh(identityCache); + } + + release() { + const state = this.__swiftHeapObjectState; + if (state.hasReleased) { + return; + } + state.hasReleased = true; + swiftHeapObjectFinalizationRegistry.unregister(state); + state.identityMap?.delete(state.pointer); + state.deinit(state.pointer); + } + } + class Library extends SwiftHeapObject { + static __construct(ptr) { + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Library_deinit, Library.prototype, null); + } + + constructor() { + const ret = instance.exports.bjs_Library_init(); + return Library.__construct(ret); + } + divider(value) { + structHelpers.M10TestModuleT7LibraryT5ShelfT7Divider.lower(value); + instance.exports.bjs_Library_divider(this.pointer); + const structValue = structHelpers.M10TestModuleT7LibraryT5ShelfT7Divider.lift(); + return structValue; + } + } + class Outer extends SwiftHeapObject { + static __construct(ptr) { + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Outer_deinit, Outer.prototype, null); + } + + constructor() { + const ret = instance.exports.bjs_Outer_init(); + return Outer.__construct(ret); + } + } + const __bjs_helpers_M10TestModuleT7LibraryT5Shelf = __bjs_createStructHelpers_M10TestModuleT7LibraryT5Shelf(); + structHelpers.M10TestModuleT7LibraryT5Shelf = __bjs_helpers_M10TestModuleT7LibraryT5Shelf; + + const __bjs_helpers_M10TestModuleT7LibraryT5ShelfT7Divider = __bjs_createStructHelpers_M10TestModuleT7LibraryT5ShelfT7Divider(); + structHelpers.M10TestModuleT7LibraryT5ShelfT7Divider = __bjs_helpers_M10TestModuleT7LibraryT5ShelfT7Divider; + + const __bjs_helpers_M10TestModuleT5OuterT5Inner = __bjs_createStructHelpers_M10TestModuleT5OuterT5Inner(); + structHelpers.M10TestModuleT5OuterT5Inner = __bjs_helpers_M10TestModuleT5OuterT5Inner; + + const __bjs_helpers_M10TestModuleT5OuterT5InnerT5Outer = __bjs_createStructHelpers_M10TestModuleT5OuterT5InnerT5Outer(); + structHelpers.M10TestModuleT5OuterT5InnerT5Outer = __bjs_helpers_M10TestModuleT5OuterT5InnerT5Outer; + + const __bjs_helpers_M10TestModuleT5OuterT5InnerT5OuterT5Inner = __bjs_createStructHelpers_M10TestModuleT5OuterT5InnerT5OuterT5Inner(); + structHelpers.M10TestModuleT5OuterT5InnerT5OuterT5Inner = __bjs_helpers_M10TestModuleT5OuterT5InnerT5OuterT5Inner; + + const exports = { + Library: Object.assign(Library, { + Shelf: { + Divider: { + init: function(slot) { + instance.exports.bjs_Library_Shelf_Divider_init(slot); + const structValue = structHelpers.M10TestModuleT7LibraryT5ShelfT7Divider.lift(); + return structValue; + }, + }, + }, + }), + Outer: Object.assign(Outer, { + Inner: { + init: function() { + instance.exports.bjs_Outer_Inner_init(); + const structValue = structHelpers.M10TestModuleT5OuterT5Inner.lift(); + return structValue; + }, + Outer: { + Inner: { + init: function() { + instance.exports.bjs_Outer_Inner_Outer_Inner_init(); + const structValue = structHelpers.M10TestModuleT5OuterT5InnerT5OuterT5Inner.lift(); + return structValue; + }, + }, + }, + }, + }), + }; + _exports = exports; + return exports; + }, + } +} \ No newline at end of file