Skip to content

Commit f1b7442

Browse files
committed
add support for generic parameters
1 parent 44ac341 commit f1b7442

File tree

7 files changed

+115
-26
lines changed

7 files changed

+115
-26
lines changed

Samples/JExtractJNISampleApp/Sources/MySwiftLibrary/ConcreteProtocolAB.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,16 @@
1313
//===----------------------------------------------------------------------===//
1414

1515
public class ConcreteProtocolAB: ProtocolA, ProtocolB {
16-
public let constant: Int64
16+
public let constantA: Int64
17+
public let constantB: Int64
1718
public var mutable: Int64 = 0
1819

1920
public func name() -> String {
2021
return "ConcreteProtocolAB"
2122
}
2223

23-
public init(constant: Int64) {
24-
self.constant = constant
24+
public init(constantA: Int64, constantB: Int64) {
25+
self.constantA = constantA
26+
self.constantB = constantB
2527
}
2628
}

Samples/JExtractJNISampleApp/Sources/MySwiftLibrary/ProtocolA.swift

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,12 @@
1313
//===----------------------------------------------------------------------===//
1414

1515
public protocol ProtocolA {
16-
var constant: Int64 { get }
16+
var constantA: Int64 { get }
1717
var mutable: Int64 { get set }
1818

1919
func name() -> String
2020
}
2121

2222
public func takeProtocol(_ proto1: any ProtocolA, _ proto2: some ProtocolA) -> Int64 {
23-
return proto1.constant + proto2.constant
24-
}
25-
26-
public func takeGenericProtocol<First: ProtocolA, Second: ProtocolA>(_ proto1: First, _ proto2: Second) -> Int64 {
27-
return proto1.constant + proto2.constant
23+
return proto1.constantA + proto2.constantA
2824
}

Samples/JExtractJNISampleApp/Sources/MySwiftLibrary/ProtocolB.swift

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,17 @@
1313
//===----------------------------------------------------------------------===//
1414

1515
public protocol ProtocolB {
16-
var constant: Int64 { get }
16+
var constantB: Int64 { get }
1717
}
1818

1919
public func takeCombinedProtocol(_ proto: some ProtocolA & ProtocolB) -> Int64 {
20-
return proto.constant + proto.constant
20+
return proto.constantA + proto.constantB
21+
}
22+
23+
public func takeGenericProtocol<First: ProtocolA, Second: ProtocolB>(_ proto1: First, _ proto2: Second) -> Int64 {
24+
return proto1.constantA + proto2.constantB
25+
}
26+
27+
public func takeCombinedGenericProtocol<T: ProtocolA & ProtocolB>(_ proto: T) -> Int64 {
28+
return proto.constantA + proto.constantB
2129
}

Samples/JExtractJNISampleApp/src/test/java/com/example/swift/ProtocolTest.java

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,34 @@ public class ProtocolTest {
2323
@Test
2424
void takeProtocol() {
2525
try (var arena = SwiftArena.ofConfined()) {
26-
ConcreteProtocolAB proto1 = ConcreteProtocolAB.init(10, arena);
27-
ConcreteProtocolAB proto2 = ConcreteProtocolAB.init(20, arena);
26+
ConcreteProtocolAB proto1 = ConcreteProtocolAB.init(10, 5, arena);
27+
ConcreteProtocolAB proto2 = ConcreteProtocolAB.init(20, 1, arena);
2828
assertEquals(30, MySwiftLibrary.takeProtocol(proto1, proto2));
2929
}
3030
}
3131

3232
@Test
3333
void takeCombinedProtocol() {
3434
try (var arena = SwiftArena.ofConfined()) {
35-
ConcreteProtocolAB proto1 = ConcreteProtocolAB.init(10, arena);
36-
assertEquals(20, MySwiftLibrary.takeCombinedProtocol(proto1));
35+
ConcreteProtocolAB proto1 = ConcreteProtocolAB.init(10, 5, arena);
36+
assertEquals(15, MySwiftLibrary.takeCombinedProtocol(proto1));
37+
}
38+
}
39+
40+
@Test
41+
void takeGenericProtocol() {
42+
try (var arena = SwiftArena.ofConfined()) {
43+
ConcreteProtocolAB proto1 = ConcreteProtocolAB.init(10, 5, arena);
44+
ConcreteProtocolAB proto2 = ConcreteProtocolAB.init(20, 1, arena);
45+
assertEquals(11, MySwiftLibrary.takeGenericProtocol(proto1, proto2));
46+
}
47+
}
48+
49+
@Test
50+
void takeCombinedGenericProtocol() {
51+
try (var arena = SwiftArena.ofConfined()) {
52+
ConcreteProtocolAB proto1 = ConcreteProtocolAB.init(10, 5, arena);
53+
assertEquals(15, MySwiftLibrary.takeCombinedGenericProtocol(proto1));
3754
}
3855
}
3956
}

Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaTranslation.swift

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@ extension JNISwift2JavaGenerator {
8181
let nativeTranslation = NativeJavaTranslation(
8282
config: self.config,
8383
javaPackage: self.javaPackage,
84-
javaClassLookupTable: self.javaClassLookupTable
84+
javaClassLookupTable: self.javaClassLookupTable,
85+
knownTypes: self.knownTypes
8586
)
8687

8788
let methodName = "" // TODO: Used for closures, replace with better name?
@@ -167,7 +168,8 @@ extension JNISwift2JavaGenerator {
167168
let nativeTranslation = NativeJavaTranslation(
168169
config: self.config,
169170
javaPackage: self.javaPackage,
170-
javaClassLookupTable: self.javaClassLookupTable
171+
javaClassLookupTable: self.javaClassLookupTable,
172+
knownTypes: self.knownTypes
171173
)
172174

173175
// Types with no parent will be outputted inside a "module" class.
@@ -440,7 +442,18 @@ extension JNISwift2JavaGenerator {
440442
javaGenericName: "$T\(parameterPosition)"
441443
)
442444

443-
case .metatype, .tuple, .genericParameter, .composite:
445+
case .genericParameter(let generic):
446+
if let concreteTy = swiftType.typeIn(genericParameters: genericParameters, genericRequirements: genericRequirements) {
447+
return try translateProtocolParameter(
448+
protocolType: concreteTy,
449+
parameterName: parameterName,
450+
javaGenericName: generic.name
451+
)
452+
}
453+
454+
throw JavaTranslationError.unsupportedSwiftType(swiftType)
455+
456+
case .metatype, .tuple, .composite:
444457
throw JavaTranslationError.unsupportedSwiftType(swiftType)
445458
}
446459
}

Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+NativeTranslation.swift

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ extension JNISwift2JavaGenerator {
2121
let config: Configuration
2222
let javaPackage: String
2323
let javaClassLookupTable: JavaClassLookupTable
24+
var knownTypes: SwiftKnownTypes
2425

2526
/// Translates a Swift function into the native JNI method signature.
2627
func translate(
@@ -37,7 +38,9 @@ extension JNISwift2JavaGenerator {
3738
type: swiftParameter.type,
3839
parameterName: parameterName,
3940
methodName: methodName,
40-
parentName: parentName
41+
parentName: parentName,
42+
genericParameters: functionSignature.genericParameters,
43+
genericRequirements: functionSignature.genericRequirements
4144
)
4245
}
4346

@@ -48,7 +51,9 @@ extension JNISwift2JavaGenerator {
4851
type: selfParameter.type,
4952
parameterName: selfParameter.parameterName ?? "self",
5053
methodName: methodName,
51-
parentName: parentName
54+
parentName: parentName,
55+
genericParameters: functionSignature.genericParameters,
56+
genericRequirements: functionSignature.genericRequirements
5257
)
5358
case nil, .initializer(_), .staticMethod(_):
5459
nil
@@ -65,15 +70,19 @@ extension JNISwift2JavaGenerator {
6570
_ parameters: [SwiftParameter],
6671
translatedParameters: [TranslatedParameter],
6772
methodName: String,
68-
parentName: String
73+
parentName: String,
74+
genericParameters: [SwiftGenericParameterDeclaration],
75+
genericRequirements: [SwiftGenericRequirement]
6976
) throws -> [NativeParameter] {
7077
try zip(translatedParameters, parameters).map { translatedParameter, swiftParameter in
7178
let parameterName = translatedParameter.parameter.name
7279
return try translateParameter(
7380
type: swiftParameter.type,
7481
parameterName: parameterName,
7582
methodName: methodName,
76-
parentName: parentName
83+
parentName: parentName,
84+
genericParameters: genericParameters,
85+
genericRequirements: genericRequirements
7786
)
7887
}
7988
}
@@ -82,7 +91,9 @@ extension JNISwift2JavaGenerator {
8291
type: SwiftType,
8392
parameterName: String,
8493
methodName: String,
85-
parentName: String
94+
parentName: String,
95+
genericParameters: [SwiftGenericParameterDeclaration],
96+
genericRequirements: [SwiftGenericRequirement]
8697
) throws -> NativeParameter {
8798
switch type {
8899
case .nominal(let nominalType):
@@ -186,7 +197,17 @@ extension JNISwift2JavaGenerator {
186197
parameterName: parameterName
187198
)
188199

189-
case .metatype, .tuple, .genericParameter, .composite:
200+
case .genericParameter:
201+
if let concreteTy = type.typeIn(genericParameters: genericParameters, genericRequirements: genericRequirements) {
202+
return try translateProtocolParameter(
203+
protocolType: concreteTy,
204+
parameterName: parameterName
205+
)
206+
}
207+
208+
throw JavaTranslationError.unsupportedSwiftType(type)
209+
210+
case .metatype, .tuple, .composite:
190211
throw JavaTranslationError.unsupportedSwiftType(type)
191212
}
192213
}
@@ -613,10 +634,10 @@ extension JNISwift2JavaGenerator {
613634
#if hasFeature(ImplicitOpenExistentials)
614635
let \(existentialName) = \(inner)RawPointer$.load(as: \(inner)DynamicType$) as! any \(compositeProtocolName)
615636
#else
616-
func \(inner)doLoad<Ty>(_ ty: Ty.Type) -> any \(compositeProtocolName) {
637+
func \(inner)DoLoad<Ty>(_ ty: Ty.Type) -> any \(compositeProtocolName) {
617638
\(inner)RawPointer$.load(as: ty) as! any \(compositeProtocolName)
618639
}
619-
let \(existentialName) = _openExistential(\(inner)DynamicType$, do: \(inner)doLoad)
640+
let \(existentialName) = _openExistential(\(inner)DynamicType$, do: \(inner)DoLoad)
620641
#endif
621642
"""
622643
)
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,38 @@ extension SwiftType {
2727
genericRequirements: genericRequirements
2828
)
2929
}
30+
31+
/// Returns the protocol type if this is a generic parameter in the list
32+
func typeIn(
33+
genericParameters: [SwiftGenericParameterDeclaration],
34+
genericRequirements: [SwiftGenericRequirement]
35+
) -> SwiftType? {
36+
switch self {
37+
case .genericParameter(let genericParam):
38+
if genericParameters.contains(genericParam) {
39+
let types: [SwiftType] = genericRequirements.compactMap {
40+
guard case .inherits(let left, let right) = $0, left == self else {
41+
return nil
42+
}
43+
return right
44+
}
45+
46+
if types.isEmpty {
47+
// TODO: Any??
48+
return nil
49+
} else if types.count == 1 {
50+
return types.first!
51+
} else {
52+
return .composite(types)
53+
}
54+
}
55+
56+
return nil
57+
58+
default:
59+
return nil
60+
}
61+
}
3062
}
3163

3264
private func representativeConcreteType(

0 commit comments

Comments
 (0)