[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