Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,15 @@ public final class ProtocolParameterOverloads {
result + callback.value() + extra
}
}

public final class ProtocolPropertyService {
public var callback: any OverloadedCallback

public init(callback: some OverloadedCallback) {
self.callback = callback
}

public func read() -> Int64 {
callback.value()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,15 @@ void overloadedInitializersAndMethodsAcceptJavaCallbacks() {
assertEquals(27, second.calculate(callback, 2));
}
}

@Test
void propertySetterAcceptsAndRetainsJavaCallback() {
try (var arena = SwiftArena.ofConfined()) {
var service = ProtocolPropertyService.init(() -> 10, arena);
assertEquals(10, service.read());
service.setCallback(() -> 42);
assertEquals(42, service.read());
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,14 @@ extension JNISwift2JavaGenerator {
)
}

/// Initializer overloads can share a protocol adapter even when their Java
/// names are disambiguated. Other declarations use the Java name, which is
/// also a valid Swift identifier for operators and Java keywords.
static func protocolWrapperMethodName(for decl: ExtractedFunc, javaName: String) -> String {
if case .initializer = decl.apiKind { return decl.name }
return javaName
}

func translate(_ decl: ExtractedFunc) throws -> TranslatedFunctionDecl {
let nativeTranslation = NativeJavaTranslation(
config: self.config,
Expand Down Expand Up @@ -226,6 +234,7 @@ extension JNISwift2JavaGenerator {
functionSignature: decl.functionSignature,
translatedFunctionSignature: translatedFunctionSignature,
methodName: javaName,
protocolWrapperMethodName: Self.protocolWrapperMethodName(for: decl, javaName: javaName),
parentName: parentName,
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ extension JNISwift2JavaGenerator {
functionSignature: SwiftFunctionSignature,
translatedFunctionSignature: TranslatedFunctionSignature,
methodName: String,
protocolWrapperMethodName: String,
parentName: SwiftQualifiedTypeName
) throws -> NativeFunctionSignature {
let parameters = try zip(translatedFunctionSignature.parameters, functionSignature.parameters).map {
Expand All @@ -42,6 +43,7 @@ extension JNISwift2JavaGenerator {
type: swiftParameter.type,
parameterName: parameterName,
methodName: methodName,
protocolWrapperMethodName: protocolWrapperMethodName,
parentName: parentName,
genericParameters: functionSignature.genericParameters,
genericRequirements: functionSignature.genericRequirements
Expand Down Expand Up @@ -74,6 +76,7 @@ extension JNISwift2JavaGenerator {
type: swiftType,
parameterName: "selfPointer",
methodName: methodName,
protocolWrapperMethodName: protocolWrapperMethodName,
parentName: parentName,
genericParameters: functionSignature.genericParameters,
genericRequirements: functionSignature.genericRequirements
Expand All @@ -91,6 +94,7 @@ extension JNISwift2JavaGenerator {
type: .metatype(selfType),
parameterName: "selfTypePointer",
methodName: methodName,
protocolWrapperMethodName: protocolWrapperMethodName,
parentName: parentName,
genericParameters: functionSignature.genericParameters,
genericRequirements: functionSignature.genericRequirements
Expand Down Expand Up @@ -121,6 +125,7 @@ extension JNISwift2JavaGenerator {
type: SwiftType,
parameterName: String,
methodName: String,
protocolWrapperMethodName: String,
parentName: SwiftQualifiedTypeName,
genericParameters: [SwiftGenericParameterDeclaration],
genericRequirements: [SwiftGenericRequirement]
Expand Down Expand Up @@ -277,7 +282,7 @@ extension JNISwift2JavaGenerator {
case .opaque(let proto), .existential(let proto):
return try translateProtocolParameter(
protocolType: proto,
methodName: methodName,
methodName: protocolWrapperMethodName,
parameterName: parameterName,
parentName: parentName
)
Expand All @@ -286,7 +291,7 @@ extension JNISwift2JavaGenerator {
if let concreteTy = type.typeIn(genericParameters: genericParameters, genericRequirements: genericRequirements) {
return try translateProtocolParameter(
protocolType: concreteTy,
methodName: methodName,
methodName: protocolWrapperMethodName,
parameterName: parameterName,
parentName: parentName
)
Expand All @@ -309,6 +314,7 @@ extension JNISwift2JavaGenerator {
type: elements[0].type,
parameterName: parameterName,
methodName: methodName,
protocolWrapperMethodName: protocolWrapperMethodName,
parentName: parentName,
genericParameters: genericParameters,
genericRequirements: genericRequirements
Expand All @@ -319,6 +325,7 @@ extension JNISwift2JavaGenerator {
elements: elements,
parameterName: parameterName,
methodName: methodName,
protocolWrapperMethodName: protocolWrapperMethodName,
parentName: parentName,
genericParameters: genericParameters,
genericRequirements: genericRequirements
Expand All @@ -333,6 +340,7 @@ extension JNISwift2JavaGenerator {
elements: [SwiftTupleElement],
parameterName: String,
methodName: String,
protocolWrapperMethodName: String,
parentName: SwiftQualifiedTypeName,
genericParameters: [SwiftGenericParameterDeclaration],
genericRequirements: [SwiftGenericRequirement]
Expand All @@ -346,6 +354,7 @@ extension JNISwift2JavaGenerator {
type: element.type,
parameterName: elementParamName,
methodName: methodName,
protocolWrapperMethodName: protocolWrapperMethodName,
parentName: parentName,
genericParameters: genericParameters,
genericRequirements: genericRequirements
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -532,7 +532,7 @@ extension JNISwift2JavaGenerator {
return
}

printAllSwiftFunctionHelperClasses(&printer, decl)
printAllSwiftFunctionHelperClasses(&printer, decl, translatedDecl)

printCDecl(
&printer,
Expand All @@ -550,21 +550,21 @@ extension JNISwift2JavaGenerator {
private func printAllSwiftFunctionHelperClasses(
_ printer: inout SwiftPrinter,
_ decl: ExtractedFunc,
_ translatedDecl: TranslatedFunctionDecl,
) {
// Emit the `@JavaInterface` Swift wrappers for any `@escaping` closure parameters.
if let translatedDecl = translatedDecl(for: decl) {
printEscapingClosureSwiftFunctionHelperClasses(&printer, translatedDecl)
}
printEscapingClosureSwiftFunctionHelperClasses(&printer, translatedDecl)

// Emit the `@JavaInterface` Swift wrappers any existential / protocol parameters.
printProtocolParameterSwiftFunctionHelperClasses(&printer, decl)
printProtocolParameterSwiftFunctionHelperClasses(&printer, decl, javaName: translatedDecl.name)
}

/// Emits Swift wrapper types for any parameter type that is a protocol
/// (or a `some`/`any`/generic constraint bound to protocols).
private func printProtocolParameterSwiftFunctionHelperClasses(
_ printer: inout SwiftPrinter,
_ decl: ExtractedFunc,
javaName: String,
) {
let protocolParameters = decl.functionSignature.parameters.compactMap { parameter in
if let concreteType = parameter.type.typeIn(
Expand Down Expand Up @@ -618,7 +618,10 @@ extension JNISwift2JavaGenerator {
fatalError()
}
let swiftClassName = JNISwift2JavaGenerator.protocolParameterWrapperClassName(
methodName: decl.name,
methodName: JavaTranslation.protocolWrapperMethodName(
for: decl,
javaName: javaName
),
parameterName: parameterName,
parentName: decl.parentType?.asNominalType?.nominalTypeDecl.qualifiedTypeName ?? SwiftQualifiedTypeName(swiftModuleName),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,52 @@ struct JNIProtocolParameterOverloadTests {
#expect(output.components(separatedBy: "final class \(name):").count - 1 == 1)
}
}

@Test("Protocol adapters use the same names in declarations and conversions")
func renamedMethodsAndSetter() throws {
var config = Configuration()
config.swiftModule = "SwiftModule"
config.enableJavaCallbacks = true
let analyzer = makeSwiftJavaAnalyzer(config: config)
try analyzer.analyze(
path: "/fake/Adapters.swiftinterface",
text: """
public protocol Store { func load() -> String }
public struct Service {
public var store: any Store
public init(store: some Store)
public init(store: some Store, extra: Int64)
public init(first store: some Store)
public init(second store: some Store)
public func use(first value: some Store)
public func use(second value: some Store)
public func `default`(_ value: some Store)
}
"""
)
let generator = JNISwift2JavaGenerator(
config: config,
translator: analyzer,
javaPackage: "com.example.swift",
swiftOutputDirectory: "/fake",
javaOutputDirectory: "/fake",
javaClassLookupTable: [:],
moduleJavaPackages: [:]
)
var printer = SwiftPrinter(mode: .accumulateAll)
try generator.writeSwiftThunkSources(&printer)
let output = printer.finalize()
for (name, references) in [
("_Service_setStore_newValue_Wrapper", 1),
("_Service_init_store_Wrapper", 4),
("_Service_useFirst_value_Wrapper", 1),
("_Service_useSecond_value_Wrapper", 1),
("_Service_default__value_Wrapper", 1),
] {
#expect(output.components(separatedBy: "final class \(name):").count - 1 == 1)
#expect(output.components(separatedBy: "= \(name)(").count - 1 == references)
}
#expect(!output.contains("_Service_store_newValue_Wrapper"))
}

}
Loading