Skip to content

Commit 885b45a

Browse files
committed
Go through nominal type resolution when translating types.
When determining how to translate a Swift nominal type for Java, go through the nominal lookup mechanism so we will (1) only find types that we actually know about, rather than guessing, and (2) lazily form the imported type record so we can handle seeing types out-of-order.
1 parent f87dd0e commit 885b45a

File tree

5 files changed

+64
-51
lines changed

5 files changed

+64
-51
lines changed

Sources/JExtractSwift/ImportedDecls.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public struct ImportedNominalType: ImportedDecl {
4343
TranslatedType(
4444
cCompatibleConvention: .direct,
4545
originalSwiftType: "\(raw: swiftTypeName)",
46-
cCompatibleSwiftType: "\(raw: swiftTypeName)",
46+
cCompatibleSwiftType: "UnsafeRawPointer",
4747
cCompatibleJavaMemoryLayout: .heapObject,
4848
javaType: javaType
4949
)

Sources/JExtractSwift/Swift2JavaTranslator.swift

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,51 @@ extension Swift2JavaTranslator {
182182

183183
}
184184

185+
// ==== ----------------------------------------------------------------------------------------------------------------
186+
// MARK: Type translation
187+
extension Swift2JavaTranslator {
188+
/// Try to resolve the given nominal type node into its imported
189+
/// representation.
190+
func importedNominalType(
191+
_ nominal: some DeclGroupSyntax & NamedDeclSyntax
192+
) -> ImportedNominalType? {
193+
if !nominal.shouldImport(log: log) {
194+
return nil
195+
}
196+
197+
guard let fullName = nominalResolution.fullyQualifiedName(of: nominal) else {
198+
return nil
199+
}
200+
201+
if let alreadyImported = importedTypes[fullName] {
202+
return alreadyImported
203+
}
204+
205+
// Determine the nominal type kind.
206+
let kind: NominalTypeKind
207+
switch Syntax(nominal).as(SyntaxEnum.self) {
208+
case .actorDecl: kind = .actor
209+
case .classDecl: kind = .class
210+
case .enumDecl: kind = .enum
211+
case .structDecl: kind = .struct
212+
default: return nil
213+
}
214+
215+
let importedNominal = ImportedNominalType(
216+
swiftTypeName: fullName,
217+
javaType: .class(
218+
package: javaPackage,
219+
name: fullName
220+
),
221+
swiftMangledName: nominal.mangledNameFromComment,
222+
kind: kind
223+
)
224+
225+
importedTypes[fullName] = importedNominal
226+
return importedNominal
227+
}
228+
}
229+
185230
// ==== ----------------------------------------------------------------------------------------------------------------
186231
// MARK: Errors
187232

Sources/JExtractSwift/Swift2JavaVisitor.swift

Lines changed: 2 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -38,40 +38,8 @@ final class Swift2JavaVisitor: SyntaxVisitor {
3838
super.init(viewMode: .all)
3939
}
4040

41-
/// Try to resolve the given nominal type node into its imported
42-
/// representation.
43-
func resolveNominalType(
44-
_ nominal: some DeclGroupSyntax & NamedDeclSyntax,
45-
kind: NominalTypeKind
46-
) -> ImportedNominalType? {
47-
if !nominal.shouldImport(log: log) {
48-
return nil
49-
}
50-
51-
guard let fullName = translator.nominalResolution.fullyQualifiedName(of: nominal) else {
52-
return nil
53-
}
54-
55-
if let alreadyImported = translator.importedTypes[fullName] {
56-
return alreadyImported
57-
}
58-
59-
let importedNominal = ImportedNominalType(
60-
swiftTypeName: fullName,
61-
javaType: .class(
62-
package: targetJavaPackage,
63-
name: fullName
64-
),
65-
swiftMangledName: nominal.mangledNameFromComment,
66-
kind: kind
67-
)
68-
69-
translator.importedTypes[fullName] = importedNominal
70-
return importedNominal
71-
}
72-
7341
override func visit(_ node: ClassDeclSyntax) -> SyntaxVisitorContinueKind {
74-
guard let importedNominalType = resolveNominalType(node, kind: .class) else {
42+
guard let importedNominalType = translator.importedNominalType(node) else {
7543
return .skipChildren
7644
}
7745

@@ -90,7 +58,7 @@ final class Swift2JavaVisitor: SyntaxVisitor {
9058
// Resolve the extended type of the extension as an imported nominal, and
9159
// recurse if we found it.
9260
guard let nominal = translator.nominalResolution.extendedType(of: node),
93-
let importedNominalType = resolveNominalType(nominal, kind: .class) else {
61+
let importedNominalType = translator.importedNominalType(nominal) else {
9462
return .skipChildren
9563
}
9664

Sources/JExtractSwift/TranslatedType.swift

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ extension Swift2JavaVisitor {
116116
}
117117

118118
// Identify the various pointer types from the standard library.
119-
if let (requiresArgument, _, _) = name.isNameOfSwiftPointerType {
119+
if let (requiresArgument, _, hasCount) = name.isNameOfSwiftPointerType, !hasCount {
120120
// Dig out the pointee type if needed.
121121
if requiresArgument {
122122
guard let genericArguments else {
@@ -144,20 +144,14 @@ extension Swift2JavaVisitor {
144144
throw TypeTranslationError.unexpectedGenericArguments(type, genericArguments)
145145
}
146146

147-
// Nested types aren't mapped into Java.
148-
if parent != nil {
149-
throw TypeTranslationError.nestedType(type)
147+
// Look up the imported types by name to resolve it to a nominal type.
148+
let swiftTypeName = type.trimmedDescription // FIXME: This is a hack.
149+
guard let resolvedNominal = translator.nominalResolution.resolveNominalType(swiftTypeName),
150+
let importedNominal = translator.importedNominalType(resolvedNominal) else {
151+
throw TypeTranslationError.unknown(type)
150152
}
151153

152-
// Swift types are passed indirectly.
153-
// FIXME: Look up type names to figure out which ones are exposed and how.
154-
return TranslatedType(
155-
cCompatibleConvention: .indirect,
156-
originalSwiftType: type,
157-
cCompatibleSwiftType: "UnsafeMutablePointer<\(type)>",
158-
cCompatibleJavaMemoryLayout: .heapObject,
159-
javaType: .class(package: nil, name: name)
160-
)
154+
return importedNominal.translatedType
161155
}
162156
}
163157

@@ -286,6 +280,6 @@ enum TypeTranslationError: Error {
286280
/// Missing generic arguments.
287281
case missingGenericArguments(TypeSyntax)
288282

289-
/// Type syntax nodes cannot be mapped.
290-
case nestedType(TypeSyntax)
283+
/// Unknown nominal type.
284+
case unknown(TypeSyntax)
291285
}

Tests/JExtractSwiftTests/FuncImportTests.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,12 @@ final class MethodImportTests {
5353
5454
@objc deinit
5555
}
56+
57+
// FIXME: Hack to allow us to translate "String", even though it's not
58+
// actually available
59+
// MANGLED NAME: $ss
60+
public class String {
61+
}
5662
"""
5763

5864
@Test func method_helloWorld() async throws {
@@ -161,7 +167,7 @@ final class MethodImportTests {
161167
* public func globalTakeIntLongString(i32: Int32, l: Int64, s: String)
162168
* }
163169
*/
164-
public static void globalTakeIntLongString(int i32, long l, String s) {
170+
public static void globalTakeIntLongString(int i32, long l, com.example.swift.String s) {
165171
var mh$ = globalTakeIntLongString.HANDLE;
166172
try {
167173
if (TRACE_DOWNCALLS) {

0 commit comments

Comments
 (0)