Skip to content

Commit 7fcdbe8

Browse files
committed
[JExtract] Translate generic parameters
* Integrate `SwiftLexicalLookup` for unqualified type lookups * Introduce `SwiftTypeLookupContext` as a facade for `SwiftLexicalLookup` and a cached conversion from Syntax to `SwiftTypeDeclaration` instance. This wraps and replaces `SwiftSymbolTable`. * Introduce `SwiftGenericParameterDeclration` as a subclass of `SwiftTypeDeclaration` to represent generic parameters. * Store generic parameters and requirements in `SwiftFunctionSignature`. * `SwiftType.representativeConcreteTypeIn()` for getting `Data` from `T: DataProtocol` type.
1 parent 4495da6 commit 7fcdbe8

21 files changed

+567
-178
lines changed

Package.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,7 @@ let package = Package(
422422
name: "JExtractSwiftLib",
423423
dependencies: [
424424
.product(name: "SwiftBasicFormat", package: "swift-syntax"),
425+
.product(name: "SwiftLexicalLookup", package: "swift-syntax"),
425426
.product(name: "SwiftSyntax", package: "swift-syntax"),
426427
.product(name: "SwiftSyntaxBuilder", package: "swift-syntax"),
427428
.product(name: "ArgumentParser", package: "swift-argument-parser"),

Sources/JExtractSwiftLib/FFM/CDeclLowering/CRepresentation.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ extension CType {
6868
case .optional(let wrapped) where wrapped.isPointer:
6969
try self.init(cdeclType: wrapped)
7070

71-
case .metatype, .optional, .tuple, .opaque, .existential:
71+
case .genericParameter, .metatype, .optional, .tuple, .opaque, .existential:
7272
throw CDeclToCLoweringError.invalidCDeclType(cdeclType)
7373
}
7474
}
@@ -98,7 +98,7 @@ extension CFunction {
9898

9999
enum CDeclToCLoweringError: Error {
100100
case invalidCDeclType(SwiftType)
101-
case invalidNominalType(SwiftNominalTypeDeclaration)
101+
case invalidNominalType(SwiftTypeDeclaration)
102102
case invalidFunctionConvention(SwiftFunctionType)
103103
}
104104

Sources/JExtractSwiftLib/FFM/CDeclLowering/FFMSwift2JavaGenerator+FunctionLowering.swift

Lines changed: 38 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@ extension FFMSwift2JavaGenerator {
2626
) throws -> LoweredFunctionSignature {
2727
let signature = try SwiftFunctionSignature(
2828
decl,
29-
enclosingType: try enclosingType.map { try SwiftType($0, symbolTable: symbolTable) },
30-
symbolTable: symbolTable
29+
enclosingType: try enclosingType.map { try SwiftType($0, lookupContext: lookupContext) },
30+
lookupContext: lookupContext
3131
)
32-
return try CdeclLowering(symbolTable: symbolTable).lowerFunctionSignature(signature)
32+
return try CdeclLowering(symbolTable: lookupContext.symbolTable).lowerFunctionSignature(signature)
3333
}
3434

3535
/// Lower the given initializer to a C-compatible entrypoint,
@@ -42,11 +42,11 @@ extension FFMSwift2JavaGenerator {
4242
) throws -> LoweredFunctionSignature {
4343
let signature = try SwiftFunctionSignature(
4444
decl,
45-
enclosingType: try enclosingType.map { try SwiftType($0, symbolTable: symbolTable) },
46-
symbolTable: symbolTable
45+
enclosingType: try enclosingType.map { try SwiftType($0, lookupContext: lookupContext) },
46+
lookupContext: lookupContext
4747
)
4848

49-
return try CdeclLowering(symbolTable: symbolTable).lowerFunctionSignature(signature)
49+
return try CdeclLowering(symbolTable: lookupContext.symbolTable).lowerFunctionSignature(signature)
5050
}
5151

5252
/// Lower the given variable decl to a C-compatible entrypoint,
@@ -66,10 +66,10 @@ extension FFMSwift2JavaGenerator {
6666
let signature = try SwiftFunctionSignature(
6767
decl,
6868
isSet: isSet,
69-
enclosingType: try enclosingType.map { try SwiftType($0, symbolTable: symbolTable) },
70-
symbolTable: symbolTable
69+
enclosingType: try enclosingType.map { try SwiftType($0, lookupContext: lookupContext) },
70+
lookupContext: lookupContext
7171
)
72-
return try CdeclLowering(symbolTable: symbolTable).lowerFunctionSignature(signature)
72+
return try CdeclLowering(symbolTable: lookupContext.symbolTable).lowerFunctionSignature(signature)
7373
}
7474
}
7575

@@ -98,18 +98,22 @@ struct CdeclLowering {
9898
try lowerParameter(
9999
selfParameter.type,
100100
convention: selfParameter.convention,
101-
parameterName: selfParameter.parameterName ?? "self"
101+
parameterName: selfParameter.parameterName ?? "self",
102+
genericParameters: signature.genericParameters,
103+
genericRequirements: signature.genericRequirements
102104
)
103105
case nil, .initializer(_), .staticMethod(_):
104106
nil
105107
}
106108

107109
// Lower all of the parameters.
108110
let loweredParameters = try signature.parameters.enumerated().map { (index, param) in
109-
try lowerParameter(
111+
return try lowerParameter(
110112
param.type,
111113
convention: param.convention,
112-
parameterName: param.parameterName ?? "_\(index)"
114+
parameterName: param.parameterName ?? "_\(index)",
115+
genericParameters: signature.genericParameters,
116+
genericRequirements: signature.genericRequirements
113117
)
114118
}
115119

@@ -142,7 +146,9 @@ struct CdeclLowering {
142146
func lowerParameter(
143147
_ type: SwiftType,
144148
convention: SwiftParameterConvention,
145-
parameterName: String
149+
parameterName: String,
150+
genericParameters: [SwiftGenericParameterDeclaration],
151+
genericRequirements: [SwiftGenericRequirement]
146152
) throws -> LoweredParameter {
147153
// If there is a 1:1 mapping between this Swift type and a C type, we just
148154
// return it.
@@ -257,7 +263,7 @@ struct CdeclLowering {
257263
guard let genericArgs = nominal.genericArguments, genericArgs.count == 1 else {
258264
throw LoweringError.unhandledType(type)
259265
}
260-
return try lowerOptionalParameter(genericArgs[0], convention: convention, parameterName: parameterName)
266+
return try lowerOptionalParameter(genericArgs[0], convention: convention, parameterName: parameterName, genericParameters: genericParameters, genericRequirements: genericRequirements)
261267

262268
case .string:
263269
// 'String' is passed in by C string. i.e. 'UnsafePointer<Int8>' ('const uint8_t *')
@@ -300,7 +306,7 @@ struct CdeclLowering {
300306

301307
case .tuple(let tuple):
302308
if tuple.count == 1 {
303-
return try lowerParameter(tuple[0], convention: convention, parameterName: parameterName)
309+
return try lowerParameter(tuple[0], convention: convention, parameterName: parameterName, genericParameters: genericParameters, genericRequirements: genericRequirements)
304310
}
305311
if convention == .inout {
306312
throw LoweringError.inoutNotSupported(type)
@@ -310,7 +316,7 @@ struct CdeclLowering {
310316
for (idx, element) in tuple.enumerated() {
311317
// FIXME: Use tuple element label.
312318
let cdeclName = "\(parameterName)_\(idx)"
313-
let lowered = try lowerParameter(element, convention: convention, parameterName: cdeclName)
319+
let lowered = try lowerParameter(element, convention: convention, parameterName: cdeclName, genericParameters: genericParameters, genericRequirements: genericRequirements)
314320

315321
parameters.append(contentsOf: lowered.cdeclParameters)
316322
conversions.append(lowered.conversion)
@@ -330,20 +336,14 @@ struct CdeclLowering {
330336
conversion: conversion
331337
)
332338

333-
case .opaque(let proto), .existential(let proto):
334-
// If the protocol has a known representative implementation, e.g. `String` for `StringProtocol`
335-
// Translate it as the concrete type.
336-
// NOTE: This is a temporary workaround until we add support for generics.
337-
if
338-
let knownProtocol = proto.asNominalTypeDeclaration?.knownTypeKind,
339-
let concreteTy = knownTypes.representativeType(of: knownProtocol)
340-
{
341-
return try lowerParameter(concreteTy, convention: convention, parameterName: parameterName)
339+
case .opaque, .existential, .genericParameter:
340+
if let concreteTy = type.representativeConcreteTypeIn(knownTypes: knownTypes, genericParameters: genericParameters, genericRequirements: genericRequirements) {
341+
return try lowerParameter(concreteTy, convention: convention, parameterName: parameterName, genericParameters: genericParameters, genericRequirements: genericRequirements)
342342
}
343343
throw LoweringError.unhandledType(type)
344344

345345
case .optional(let wrapped):
346-
return try lowerOptionalParameter(wrapped, convention: convention, parameterName: parameterName)
346+
return try lowerOptionalParameter(wrapped, convention: convention, parameterName: parameterName, genericParameters: genericParameters, genericRequirements: genericRequirements)
347347
}
348348
}
349349

@@ -354,7 +354,9 @@ struct CdeclLowering {
354354
func lowerOptionalParameter(
355355
_ wrappedType: SwiftType,
356356
convention: SwiftParameterConvention,
357-
parameterName: String
357+
parameterName: String,
358+
genericParameters: [SwiftGenericParameterDeclaration],
359+
genericRequirements: [SwiftGenericRequirement]
358360
) throws -> LoweredParameter {
359361
// If there is a 1:1 mapping between this Swift type and a C type, lower it to 'UnsafePointer<T>?'
360362
if let _ = try? CType(cdeclType: wrappedType) {
@@ -398,18 +400,15 @@ struct CdeclLowering {
398400
conversion: .pointee(.typedPointer(.optionalChain(.placeholder), swiftType: wrappedType))
399401
)
400402

401-
case .existential(let proto), .opaque(let proto):
402-
if
403-
let knownProtocol = proto.asNominalTypeDeclaration?.knownTypeKind,
404-
let concreteTy = knownTypes.representativeType(of: knownProtocol)
405-
{
406-
return try lowerOptionalParameter(concreteTy, convention: convention, parameterName: parameterName)
403+
case .existential, .opaque, .genericParameter:
404+
if let concreteTy = wrappedType.representativeConcreteTypeIn(knownTypes: knownTypes, genericParameters: genericParameters, genericRequirements: genericRequirements) {
405+
return try lowerOptionalParameter(concreteTy, convention: convention, parameterName: parameterName, genericParameters: genericParameters, genericRequirements: genericRequirements)
407406
}
408407
throw LoweringError.unhandledType(.optional(wrappedType))
409408

410409
case .tuple(let tuple):
411410
if tuple.count == 1 {
412-
return try lowerOptionalParameter(tuple[0], convention: convention, parameterName: parameterName)
411+
return try lowerOptionalParameter(tuple[0], convention: convention, parameterName: parameterName, genericParameters: genericParameters, genericRequirements: genericRequirements)
413412
}
414413
throw LoweringError.unhandledType(.optional(wrappedType))
415414

@@ -514,7 +513,7 @@ struct CdeclLowering {
514513
// Custom types are not supported yet.
515514
throw LoweringError.unhandledType(type)
516515

517-
case .function, .metatype, .optional, .tuple, .existential, .opaque:
516+
case .genericParameter, .function, .metatype, .optional, .tuple, .existential, .opaque:
518517
// TODO: Implement
519518
throw LoweringError.unhandledType(type)
520519
}
@@ -668,7 +667,7 @@ struct CdeclLowering {
668667
conversion: .tupleExplode(conversions, name: outParameterName)
669668
)
670669

671-
case .function, .optional, .existential, .opaque:
670+
case .genericParameter, .function, .optional, .existential, .opaque:
672671
throw LoweringError.unhandledType(type)
673672
}
674673
}
@@ -754,7 +753,9 @@ public struct LoweredFunctionSignature: Equatable {
754753
selfParameter: nil,
755754
parameters: allLoweredParameters,
756755
result: SwiftResult(convention: .direct, type: result.cdeclResultType),
757-
effectSpecifiers: []
756+
effectSpecifiers: [],
757+
genericParameters: [],
758+
genericRequirements: []
758759
)
759760
}
760761
}

Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaTranslation.swift

Lines changed: 54 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ extension FFMSwift2JavaGenerator {
2424

2525
let translated: TranslatedFunctionDecl?
2626
do {
27-
let translation = JavaTranslation(symbolTable: self.symbolTable)
27+
let translation = JavaTranslation(knownTypes: SwiftKnownTypes(symbolTable: lookupContext.symbolTable))
2828
translated = try translation.translate(decl)
2929
} catch {
3030
self.log.info("Failed to translate: '\(decl.swiftDecl.qualifiedNameForDebug)'; \(error)")
@@ -115,8 +115,8 @@ extension FFMSwift2JavaGenerator {
115115
struct JavaTranslation {
116116
var knownTypes: SwiftKnownTypes
117117

118-
init(symbolTable: SwiftSymbolTable) {
119-
self.knownTypes = SwiftKnownTypes(symbolTable: symbolTable)
118+
init(knownTypes: SwiftKnownTypes) {
119+
self.knownTypes = knownTypes
120120
}
121121

122122
func translate(
@@ -256,7 +256,9 @@ extension FFMSwift2JavaGenerator {
256256
convention: swiftSelf.convention,
257257
parameterName: swiftSelf.parameterName ?? "self",
258258
loweredParam: loweredFunctionSignature.selfParameter!,
259-
methodName: methodName
259+
methodName: methodName,
260+
genericParameters: swiftSignature.genericParameters,
261+
genericRequirements: swiftSignature.genericRequirements
260262
)
261263
} else {
262264
selfParameter = nil
@@ -272,7 +274,9 @@ extension FFMSwift2JavaGenerator {
272274
convention: swiftParam.convention,
273275
parameterName: parameterName,
274276
loweredParam: loweredParam,
275-
methodName: methodName
277+
methodName: methodName,
278+
genericParameters: swiftSignature.genericParameters,
279+
genericRequirements: swiftSignature.genericRequirements
276280
)
277281
}
278282

@@ -295,7 +299,9 @@ extension FFMSwift2JavaGenerator {
295299
convention: SwiftParameterConvention,
296300
parameterName: String,
297301
loweredParam: LoweredParameter,
298-
methodName: String
302+
methodName: String,
303+
genericParameters: [SwiftGenericParameterDeclaration],
304+
genericRequirements: [SwiftGenericRequirement]
299305
) throws -> TranslatedParameter {
300306

301307
// If there is a 1:1 mapping between this Swift type and a C type, that can
@@ -352,7 +358,15 @@ extension FFMSwift2JavaGenerator {
352358
guard let genericArgs = swiftNominalType.genericArguments, genericArgs.count == 1 else {
353359
throw JavaTranslationError.unhandledType(swiftType)
354360
}
355-
return try translateOptionalParameter(wrappedType: genericArgs[0], convention: convention, parameterName: parameterName, loweredParam: loweredParam, methodName: methodName)
361+
return try translateOptionalParameter(
362+
wrappedType: genericArgs[0],
363+
convention: convention,
364+
parameterName: parameterName,
365+
loweredParam: loweredParam,
366+
methodName: methodName,
367+
genericParameters: genericParameters,
368+
genericRequirements: genericRequirements
369+
)
356370

357371
case .string:
358372
return TranslatedParameter(
@@ -399,28 +413,32 @@ extension FFMSwift2JavaGenerator {
399413
conversion: .call(.placeholder, function: "\(methodName).$toUpcallStub", withArena: true)
400414
)
401415

402-
case .existential(let proto), .opaque(let proto):
403-
// If the protocol has a known representative implementation, e.g. `String` for `StringProtocol`
404-
// Translate it as the concrete type.
405-
// NOTE: This is a temporary workaround until we add support for generics.
406-
if
407-
let knownProtocol = proto.asNominalTypeDeclaration?.knownTypeKind,
408-
let concreteTy = knownTypes.representativeType(of: knownProtocol)
409-
{
416+
case .existential, .opaque, .genericParameter:
417+
if let concreteTy = swiftType.representativeConcreteTypeIn(knownTypes: knownTypes, genericParameters: genericParameters, genericRequirements: genericRequirements) {
410418
return try translateParameter(
411419
type: concreteTy,
412420
convention: convention,
413421
parameterName: parameterName,
414422
loweredParam: loweredParam,
415-
methodName: methodName
423+
methodName: methodName,
424+
genericParameters: genericParameters,
425+
genericRequirements: genericRequirements
416426
)
417427
}
418428

419429
// Otherwise, not supported yet.
420430
throw JavaTranslationError.unhandledType(swiftType)
421431

422432
case .optional(let wrapped):
423-
return try translateOptionalParameter(wrappedType: wrapped, convention: convention, parameterName: parameterName, loweredParam: loweredParam, methodName: methodName)
433+
return try translateOptionalParameter(
434+
wrappedType: wrapped,
435+
convention: convention,
436+
parameterName: parameterName,
437+
loweredParam: loweredParam,
438+
methodName: methodName,
439+
genericParameters: genericParameters,
440+
genericRequirements: genericRequirements
441+
)
424442
}
425443
}
426444

@@ -430,12 +448,14 @@ extension FFMSwift2JavaGenerator {
430448
convention: SwiftParameterConvention,
431449
parameterName: String,
432450
loweredParam: LoweredParameter,
433-
methodName: String
451+
methodName: String,
452+
genericParameters: [SwiftGenericParameterDeclaration],
453+
genericRequirements: [SwiftGenericRequirement]
434454
) throws -> TranslatedParameter {
435455
// If there is a 1:1 mapping between this Swift type and a C type, that can
436456
// be expressed as a Java primitive type.
437457
if let cType = try? CType(cdeclType: swiftType) {
438-
var (translatedClass, lowerFunc) = switch cType.javaType {
458+
let (translatedClass, lowerFunc) = switch cType.javaType {
439459
case .int: ("OptionalInt", "toOptionalSegmentInt")
440460
case .long: ("OptionalLong", "toOptionalSegmentLong")
441461
case .double: ("OptionalDouble", "toOptionalSegmentDouble")
@@ -473,23 +493,30 @@ extension FFMSwift2JavaGenerator {
473493
],
474494
conversion: .call(.placeholder, function: "SwiftRuntime.toOptionalSegmentInstance", withArena: false)
475495
)
476-
case .existential(let proto), .opaque(let proto):
477-
if
478-
let knownProtocol = proto.asNominalTypeDeclaration?.knownTypeKind,
479-
let concreteTy = knownTypes.representativeType(of: knownProtocol)
480-
{
496+
case .existential, .opaque, .genericParameter:
497+
if let concreteTy = swiftType.representativeConcreteTypeIn(knownTypes: knownTypes, genericParameters: genericParameters, genericRequirements: genericRequirements) {
481498
return try translateOptionalParameter(
482499
wrappedType: concreteTy,
483500
convention: convention,
484501
parameterName: parameterName,
485502
loweredParam: loweredParam,
486-
methodName: methodName
503+
methodName: methodName,
504+
genericParameters: genericParameters,
505+
genericRequirements: genericRequirements
487506
)
488507
}
489508
throw JavaTranslationError.unhandledType(.optional(swiftType))
490509
case .tuple(let tuple):
491510
if tuple.count == 1 {
492-
return try translateOptionalParameter(wrappedType: tuple[0], convention: convention, parameterName: parameterName, loweredParam: loweredParam, methodName: methodName)
511+
return try translateOptionalParameter(
512+
wrappedType: tuple[0],
513+
convention: convention,
514+
parameterName: parameterName,
515+
loweredParam: loweredParam,
516+
methodName: methodName,
517+
genericParameters: genericParameters,
518+
genericRequirements: genericRequirements
519+
)
493520
}
494521
throw JavaTranslationError.unhandledType(.optional(swiftType))
495522
default:
@@ -580,7 +607,7 @@ extension FFMSwift2JavaGenerator {
580607
// TODO: Implement.
581608
throw JavaTranslationError.unhandledType(swiftType)
582609

583-
case .optional, .function, .existential, .opaque:
610+
case .genericParameter, .optional, .function, .existential, .opaque:
584611
throw JavaTranslationError.unhandledType(swiftType)
585612
}
586613

0 commit comments

Comments
 (0)