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
@@ -0,0 +1,37 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2025 Apple Inc. and the Swift.org project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of Swift.org project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//

public protocol OverloadedCallback {
func value() -> Int64
}

public final class ProtocolParameterOverloads {
public let result: Int64

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

public init(callback: some OverloadedCallback, extra: Int64) {
result = callback.value() + extra
}

public func calculate(_ callback: some OverloadedCallback) -> Int64 {
result + callback.value()
}

public func calculate(_ callback: some OverloadedCallback, extra: Int64) -> Int64 {
result + callback.value() + extra
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2025 Apple Inc. and the Swift.org project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of Swift.org project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//

package com.example.swift;

import org.junit.jupiter.api.Test;
import org.swift.swiftkit.core.SwiftArena;
import static org.junit.jupiter.api.Assertions.assertEquals;

public class ProtocolParameterOverloadsTest {
@Test
void overloadedInitializersAndMethodsAcceptJavaCallbacks() {
OverloadedCallback callback = () -> 10;
try (var arena = SwiftArena.ofConfined()) {
var first = ProtocolParameterOverloads.init(callback, arena);
var second = ProtocolParameterOverloads.init(callback, 5, arena);
assertEquals(10, first.getResult());
assertEquals(15, second.getResult());
assertEquals(20, first.calculate(callback));
assertEquals(27, second.calculate(callback, 2));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,12 @@ extension JNISwift2JavaGenerator {
parentName: decl.parentType?.asNominalType?.nominalTypeDecl.qualifiedTypeName ?? SwiftQualifiedTypeName(swiftModuleName),
)
let implementingProtocols = protocolWrappers.map(\.wrapperName).joined(separator: .comma)
// Overloads with the same protocol parameter share an identical adapter.
if let existing = emittedProtocolParameterWrappers[swiftClassName] {
precondition(existing == implementingProtocols, "Conflicting protocol adapters for \(swiftClassName)")
continue
}
emittedProtocolParameterWrappers[swiftClassName] = implementingProtocols

printer.printBraceBlock("final class \(swiftClassName): \(implementingProtocols)") { printer in
let variables: [(String, String)] = protocolWrappers.map { wrapper in
Expand Down
1 change: 1 addition & 0 deletions Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ package class JNISwift2JavaGenerator: Swift2JavaGenerator {
.map(\.swiftNominal.identity)
)
var interfaceProtocolWrappers: [ExtractedNominalType: JavaInterfaceSwiftWrapper] = [:]
var emittedProtocolParameterWrappers: [String: String] = [:]

/// Protocols that should be boxed to support returning them as `any P / some P`
private(set) var existentialProtocolBoxes: [ExtractedNominalType] = []
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2025 Apple Inc. and the Swift.org project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of Swift.org project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//

import CodePrinting
import Foundation
import JExtractSwiftLib
import SwiftJavaConfigurationShared
import Testing

@Suite
struct JNIProtocolParameterOverloadTests {
@Test("Overloads share one adapter per protocol parameter")
func identicalAdaptersAreEmittedOnce() throws {
var config = Configuration()
config.swiftModule = "SwiftModule"
config.enableJavaCallbacks = true
let analyzer = makeSwiftJavaAnalyzer(config: config)
try analyzer.analyze(
path: "/fake/Overloads.swiftinterface",
text: """
public protocol Callback { func value() -> Int64 }
public struct Client {
public init(store: some Callback)
public init(store: some Callback, extra: Int64)
}
public func use(_ callback: some Callback)
public func use(_ callback: some Callback, extra: Int64)
public func other(_ callback: some Callback)
"""
)
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 in ["_Client_init_store_Wrapper", "_SwiftModule_use_callback_Wrapper", "_SwiftModule_other_callback_Wrapper"] {
#expect(output.components(separatedBy: "final class \(name):").count - 1 == 1)
}
}
}
Loading