[K/N]: SwiftExport: Namespacing
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/swift/IrBasedSwiftGenerator.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/swift/IrBasedSwiftGenerator.kt
index a500dfb..586f787 100644
--- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/swift/IrBasedSwiftGenerator.kt
+++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/swift/IrBasedSwiftGenerator.kt
@@ -20,6 +20,7 @@
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.name.Name
+import java.util.HashMap
/**
* Generate a Swift API file for the given Kotlin IR module.
@@ -83,6 +84,7 @@
parameters = listOf(parameter(parameterName = "obj", type = T), parameter(argumentName = "slot", type = "UnsafeMutableRawPointer".type)),
genericTypes = listOf(T.name.genericParameter(constraint = "AnyObject".type)),
returnType = "UnsafeMutableRawPointer".type,
+ isStatic = true,
attributes = listOf(attribute("inline", "__always".identifier)),
visibility = private
) {
@@ -190,7 +192,7 @@
when {
property != null -> {
swiftName = property.getNameWithAssert().identifier
- path = property.parent.kotlinFqName.pathSegments().map { it.identifier }
+ path = property.parent.kotlinFqName.pathSegments().map { it.identifier } + listOf(swiftName)
val pathString = path.joinToString(separator = "_")
when {
declaration.isGetter -> cName = "__kn_get_$pathString"
@@ -206,20 +208,40 @@
}
}
- return Names(swiftName, cName, listOf("Kotlin") + path.dropLast(1), symbolName)
+ return Names(swiftName, cName, path, symbolName)
}
}
}
+ private data class Namespace<T>(
+ val name: String,
+ val elements: MutableList<T> = mutableListOf(),
+ val children: MutableMap<String, Namespace<T>> = mutableMapOf(),
+ ) {
+ fun <R> reduce(transform: (String, List<T>, List<R>) -> R): R =
+ transform(name, elements, children.map { it.value.reduce(transform) })
+
+ fun insert(path: List<String>, value: T) {
+ if (path.isEmpty()) {
+ elements.add(value)
+ return
+ }
+
+ val key = path.first()
+ val next = children.getOrPut(key) { Namespace<T>(key) }
+ next.insert(path.drop(1), value)
+ }
+ }
+
private val swiftImports = mutableListOf<SwiftCode.Import>(SwiftCode.Import.Module("Foundation"))
- private val swiftDeclarations = mutableListOf<SwiftCode.Declaration>(
+ private val swiftDeclarations = Namespace("", elements = mutableListOf<SwiftCode.Declaration>(
bridgeFromKotlin,
bridgeToKotlin,
withUnsafeSlots,
withUnsafeTemporaryBufferAllocation,
objHolder,
pointerExtensions,
- )
+ ))
// FIXME: we shouldn't manually generate c headers for our existing code, but here we are.
private val cImports = CCode.build {
@@ -239,7 +261,20 @@
)
}
- fun buildSwiftShimFile() = SwiftCode.File(swiftImports, swiftDeclarations)
+ fun buildSwiftShimFile() = SwiftCode.File(swiftImports, swiftDeclarations.reduce<SwiftCode.Declaration.Enum> { name, elements, children ->
+ SwiftCode.build {
+ enum(name, visibility = public) {
+ children.forEach { +it }
+ elements.forEach { +it }
+ }
+ }
+ }.block.declarations.map {
+ if (it is SwiftCode.Declaration.Function) {
+ it.copy(isStatic = false) // We need to patch-out 'static' from top-level free functions
+ } else {
+ it
+ }
+ })
fun buildSwiftBridgingHeader() = CCode.build {
CCode.File(cImports + pragma("clang assume_nonnull begin") + cDeclarations + pragma("clang assume_nonnull end"))
@@ -250,11 +285,12 @@
}
override fun visitProperty(declaration: IrProperty) {
- val name = declaration.name.identifier
+ val propertyNames: Names
val bridge = bridgeFor(declaration.getter!!.returnType) ?: return
val getter = declaration.getter!!.let {
val names = Names(it)
+ propertyNames = names
generateCFunction(it, names)?.also(cDeclarations::add) ?: return
val swift = generateSwiftFunction(it, names) ?: return
@@ -282,8 +318,8 @@
}
}
- swiftDeclarations.add(SwiftCode.build {
- `var`(name, type = bridge.swiftType, get = getter, set = setter)
+ swiftDeclarations.insert(propertyNames.path.dropLast(1), SwiftCode.build {
+ `var`(propertyNames.swift, type = bridge.swiftType, get = getter, set = setter)
})
}
@@ -298,7 +334,9 @@
val cFunction = generateCFunction(declaration, names)?.also { cDeclarations.add(it) } ?: return
@Suppress("unused_variable")
- val swiftFunction = generateSwiftFunction(declaration, names)?.also { swiftDeclarations.add(it) } ?: return
+ val swiftFunction = generateSwiftFunction(declaration, names)
+ ?.also { swiftDeclarations.insert(names.path.dropLast(1), it) }
+ ?: return
}
private fun isSupported(declaration: IrFunction): Boolean {
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/swift/SwiftCode.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/swift/SwiftCode.kt
index 309c948..b3c21b9 100644
--- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/swift/SwiftCode.kt
+++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/swift/SwiftCode.kt
@@ -263,17 +263,16 @@
override fun <T : Statement> T.unaryPlus() = also { this@Builder.statements.add(it) }
}
- override fun render(): String {
- listOfNotNull(
- attributes.render(),
- visibility.renderAsPrefix(),
- name,
- genericTypes.render(),
- inheritedTypes.takeIf { it.isNotEmpty() }?.joinToString(separator = " & ") { it.render() }?.let { ": $it" },
- genericTypeConstraints.takeIf { it.isNotEmpty() }?.render()?.let { "\n$it" },
- block.renderAsBlock()
- ).joinToString(separator = "")
- }
+ override fun render(): String = listOfNotNull(
+ attributes.render(),
+ visibility.renderAsPrefix(),
+ "enum ",
+ name,
+ genericTypes.render(),
+ inheritedTypes.takeIf { it.isNotEmpty() }?.joinToString(separator = " & ") { it.render() }?.let { ": $it" },
+ genericTypeConstraints.takeIf { it.isNotEmpty() }?.render()?.let { "\n$it" },
+ block.renderAsBlock().let { " $it" }
+ ).joinToString(separator = "")
}
}
@@ -863,6 +862,16 @@
fun SwiftCode.Type.isSubtypeOf(type: SwiftCode.Type) = SwiftCode.GenericConstraint(this, type, isExact = false)
+fun SwiftCode.Builder.enum(
+ name: String,
+ genericTypes: List<SwiftCode.GenericParameter> = emptyList(),
+ inheritedTypes: List<SwiftCode.Type.Nominal> = emptyList(),
+ genericTypeConstraints: List<SwiftCode.GenericConstraint> = emptyList(),
+ attributes: List<SwiftCode.Attribute> = emptyList(),
+ visibility: SwiftCode.Declaration.Visibility = SwiftCode.Declaration.Visibility.INTERNAL,
+ block: SwiftCode.DeclarationsBuilder.() -> Unit
+) = SwiftCode.Declaration.Enum(name, genericTypes, inheritedTypes, genericTypeConstraints, attributes, visibility, SwiftCode.DeclarationsBlock(block))
+
//endregion
//region Statements