Skip to content

Commit 29f45a2

Browse files
committed
Mark Sendable types as @threadsafe
1 parent ac30ee4 commit 29f45a2

File tree

4 files changed

+102
-0
lines changed

4 files changed

+102
-0
lines changed

Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,9 @@ extension FFMSwift2JavaGenerator {
278278
parentProtocol = "SwiftValue"
279279
}
280280

281+
if decl.swiftNominal.isSendable {
282+
printer.print("@ThreadSafe // Sendable")
283+
}
281284
printer.printBraceBlock("public final class \(decl.swiftNominal.name) extends FFMSwiftInstance implements \(parentProtocol)") {
282285
printer in
283286
// Constants

Sources/JExtractSwiftLib/SwiftTypes/SwiftNominalTypeDeclaration.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,22 @@ package class SwiftNominalTypeDeclaration: SwiftTypeDeclaration {
8585
super.init(moduleName: moduleName, name: node.name.text)
8686
}
8787

88+
/// Returns true if this type conforms to `Sendable` and therefore is "threadsafe".
89+
lazy var isSendable: Bool = {
90+
// Check if Sendable is in the inheritance list
91+
guard let inheritanceClause = self.syntax?.inheritanceClause else {
92+
return false
93+
}
94+
95+
for inheritedType in inheritanceClause.inheritedTypes {
96+
if inheritedType.type.trimmedDescription == "Sendable" {
97+
return true
98+
}
99+
}
100+
101+
return false
102+
}()
103+
88104
/// Determine the known standard library type for this nominal type
89105
/// declaration.
90106
private func computeKnownStandardLibraryType() -> SwiftKnownTypeDeclKind? {
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2024 Apple Inc. and the Swift.org project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of Swift.org project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
package org.swift.swiftkit.core.annotations;
16+
17+
import jdk.jfr.Description;
18+
import jdk.jfr.Label;
19+
20+
import java.lang.annotation.Documented;
21+
import java.lang.annotation.Retention;
22+
import java.lang.annotation.RetentionPolicy;
23+
import java.lang.annotation.Target;
24+
25+
import static java.lang.annotation.ElementType.*;
26+
27+
/**
28+
* Used to mark a type as thread-safe, i.e. no additional synchronization is necessary when accessing it
29+
* from multiple threads.
30+
*
31+
* <p> In SwiftJava specifically, this attribute is applied when an extracted Swift type conforms to the Swift
32+
* {@code Sendable} protocol, which is a compiler enforced mechanism to enforce thread-safety in Swift.
33+
*
34+
* @see <a href="https://developer.apple.com/documentation/Swift/Sendable">Swift Sendable API documentation</a>.
35+
*/
36+
@Documented
37+
@Label("Thread-safe")
38+
@Description("")
39+
@Target({TYPE_USE})
40+
@Retention(RetentionPolicy.RUNTIME)
41+
public @interface ThreadSafe {
42+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2024 Apple Inc. and the Swift.org project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of Swift.org project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
import JExtractSwiftLib
16+
import Testing
17+
18+
final class SendableTests {
19+
let source =
20+
"""
21+
public struct SendableStruct: Sendable {}
22+
"""
23+
24+
25+
@Test("Import: Sendable struct")
26+
func data_swiftThunk() throws {
27+
28+
try assertOutput(
29+
input: source, .ffm, .java,
30+
expectedChunks: [
31+
"""
32+
@ThreadSafe // Sendable
33+
public final class SendableStruct extends FFMSwiftInstance implements SwiftValue {
34+
static final String LIB_NAME = "SwiftModule";
35+
static final Arena LIBRARY_ARENA = Arena.ofAuto();
36+
""",
37+
]
38+
)
39+
}
40+
41+
}

0 commit comments

Comments
 (0)