From 157cb87674a7246d956e180443e75b2d76ea705c Mon Sep 17 00:00:00 2001 From: Sergey Bogolepov Date: Thu, 18 Apr 2024 17:59:26 +0300 Subject: [PATCH 1/4] Basic Swift export Minor hack: use wasm stdlib to avoid downloading the whole K/N distribution --- build.gradle.kts | 2 + gradle.properties | 1 + settings.gradle.kts | 1 + .../components/SwiftExportTranslator.kt | 32 ++++++ .../controllers/CompilerRestController.kt | 4 + .../KotlinPlaygroundRestController.kt | 1 + .../compiler/server/model/ExecutionResult.kt | 8 ++ .../model/KotlinTranslatableCompiler.kt | 3 +- .../com/compiler/server/model/Project.kt | 4 +- .../server/service/KotlinProjectExecutor.kt | 15 +++ .../com/compiler/server/SwiftConverterTest.kt | 99 +++++++++++++++++++ .../compiler/server/base/BaseExecutorTest.kt | 2 + .../server/generator/TestProjectRunner.kt | 5 + swift-export-playground/README.md | 1 + swift-export-playground/build.gradle.kts | 36 +++++++ .../src/main/kotlin/PlaygroundSirSession.kt | 31 ++++++ .../src/main/kotlin/Runner.kt | 81 +++++++++++++++ .../src/test/kotlin/Tests.kt | 81 +++++++++++++++ 18 files changed, 405 insertions(+), 2 deletions(-) create mode 100644 src/main/kotlin/com/compiler/server/compiler/components/SwiftExportTranslator.kt create mode 100644 src/test/kotlin/com/compiler/server/SwiftConverterTest.kt create mode 100644 swift-export-playground/README.md create mode 100644 swift-export-playground/build.gradle.kts create mode 100644 swift-export-playground/src/main/kotlin/PlaygroundSirSession.kt create mode 100644 swift-export-playground/src/main/kotlin/Runner.kt create mode 100644 swift-export-playground/src/test/kotlin/Tests.kt diff --git a/build.gradle.kts b/build.gradle.kts index 52282b612..8e18c403c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -41,6 +41,7 @@ allprojects { maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap") maven("https://maven.pkg.jetbrains.space/kotlin/p/wasm/experimental") maven("https://maven.pkg.jetbrains.space/public/p/compose/dev") + maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/swift-export-experimental") } afterEvaluate { dependencies { @@ -80,6 +81,7 @@ dependencies { implementation("org.jetbrains.kotlin:core:231-$kotlinIdeVersion-$kotlinIdeVersionSuffix") implementation(project(":executors", configuration = "default")) implementation(project(":common", configuration = "default")) + implementation(project(":swift-export-playground", configuration = "default")) testImplementation("org.springframework.boot:spring-boot-starter-test") { exclude(group = "org.junit.vintage", module = "junit-vintage-engine") diff --git a/gradle.properties b/gradle.properties index 27a2730d7..1886fee40 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,7 @@ systemProp.kotlinVersion=2.0.0-RC3 systemProp.kotlinIdeVersion=1.9.20-506 systemProp.kotlinIdeVersionSuffix=IJ8109.175 +systemProp.swiftExportVersion=2.0.20-dev-3080 systemProp.policy=executor.policy systemProp.indexes=indexes.json systemProp.indexesJs=indexesJs.json diff --git a/settings.gradle.kts b/settings.gradle.kts index aa2d316b6..3ab5e1358 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -3,6 +3,7 @@ include(":executors") include(":indexation") include(":common") include(":dependencies") +include(":swift-export-playground") pluginManagement { repositories { diff --git a/src/main/kotlin/com/compiler/server/compiler/components/SwiftExportTranslator.kt b/src/main/kotlin/com/compiler/server/compiler/components/SwiftExportTranslator.kt new file mode 100644 index 000000000..6c7e89095 --- /dev/null +++ b/src/main/kotlin/com/compiler/server/compiler/components/SwiftExportTranslator.kt @@ -0,0 +1,32 @@ +package com.compiler.server.compiler.components + +import com.compiler.server.model.CompilerDiagnostics +import com.compiler.server.model.SwiftExportResult +import com.compiler.server.model.toExceptionDescriptor +import component.KotlinEnvironment +import org.jetbrains.kotlin.psi.KtFile +import org.springframework.stereotype.Component +import runSwiftExport +import java.nio.file.Path + +@Component +class SwiftExportTranslator( + private val kotlinEnvironment: KotlinEnvironment, +) { + fun translate(files: List): SwiftExportResult = try { + usingTempDirectory { tempDirectory -> + val ioFiles = files.writeToIoFiles(tempDirectory) + val stdlib = kotlinEnvironment.WASM_LIBRARIES.singleOrNull { "stdlib" in it } + val swiftCode = runSwiftExport( + sourceFile = ioFiles.first(), + stdlibPath = stdlib?.let { Path.of(it) }, + ) + SwiftExportResult( + compilerDiagnostics = CompilerDiagnostics(emptyMap()), + swiftCode = swiftCode + ) + } + } catch (e: Exception) { + SwiftExportResult(swiftCode = "", exception = e.toExceptionDescriptor()) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/compiler/server/controllers/CompilerRestController.kt b/src/main/kotlin/com/compiler/server/controllers/CompilerRestController.kt index 2b646d8f4..67c1e87c4 100644 --- a/src/main/kotlin/com/compiler/server/controllers/CompilerRestController.kt +++ b/src/main/kotlin/com/compiler/server/controllers/CompilerRestController.kt @@ -28,6 +28,10 @@ class CompilerRestController(private val kotlinProjectExecutor: KotlinProjectExe KotlinTranslatableCompiler.JS -> kotlinProjectExecutor.convertToJsIr(project) KotlinTranslatableCompiler.WASM -> kotlinProjectExecutor.convertToWasm(project, debugInfo) KotlinTranslatableCompiler.COMPOSE_WASM -> kotlinProjectExecutor.convertToWasm(project, debugInfo) + KotlinTranslatableCompiler.SWIFT -> kotlinProjectExecutor.convertToSwift(project).let { + // TODO: A hack to avoid changing the return type of the function. + object : TranslationResultWithJsCode(it.swiftCode, it.compilerDiagnostics, it.exception) {} + } } } diff --git a/src/main/kotlin/com/compiler/server/controllers/KotlinPlaygroundRestController.kt b/src/main/kotlin/com/compiler/server/controllers/KotlinPlaygroundRestController.kt index 737db2cef..ee952bbb0 100644 --- a/src/main/kotlin/com/compiler/server/controllers/KotlinPlaygroundRestController.kt +++ b/src/main/kotlin/com/compiler/server/controllers/KotlinPlaygroundRestController.kt @@ -50,6 +50,7 @@ class KotlinPlaygroundRestController(private val kotlinProjectExecutor: KotlinPr debugInfo = false, ) ProjectType.JUNIT -> kotlinProjectExecutor.test(project) + ProjectType.SWIFT_EXPORT -> kotlinProjectExecutor.convertToSwift(project) } } diff --git a/src/main/kotlin/com/compiler/server/model/ExecutionResult.kt b/src/main/kotlin/com/compiler/server/model/ExecutionResult.kt index 9d7691206..f2a9af180 100644 --- a/src/main/kotlin/com/compiler/server/model/ExecutionResult.kt +++ b/src/main/kotlin/com/compiler/server/model/ExecutionResult.kt @@ -82,6 +82,14 @@ class JunitExecutionResult( override var compilerDiagnostics: CompilerDiagnostics = CompilerDiagnostics() ) : ExecutionResult(compilerDiagnostics, exception) +class SwiftExportResult( + val swiftCode: String, + override var exception: ExceptionDescriptor? = null, + @field:JsonProperty("errors") + override var compilerDiagnostics: CompilerDiagnostics = CompilerDiagnostics() +) : ExecutionResult(compilerDiagnostics, exception) + + private fun unEscapeOutput(value: String) = value.replace("&lt;".toRegex(), "<") .replace("&gt;".toRegex(), ">") .replace("\r", "") diff --git a/src/main/kotlin/com/compiler/server/model/KotlinTranslatableCompiler.kt b/src/main/kotlin/com/compiler/server/model/KotlinTranslatableCompiler.kt index 0f7430568..4bc2dc8c5 100644 --- a/src/main/kotlin/com/compiler/server/model/KotlinTranslatableCompiler.kt +++ b/src/main/kotlin/com/compiler/server/model/KotlinTranslatableCompiler.kt @@ -3,5 +3,6 @@ package com.compiler.server.model enum class KotlinTranslatableCompiler { JS, WASM, - COMPOSE_WASM + COMPOSE_WASM, + SWIFT, } \ No newline at end of file diff --git a/src/main/kotlin/com/compiler/server/model/Project.kt b/src/main/kotlin/com/compiler/server/model/Project.kt index b8afd6fee..dcb57cc40 100644 --- a/src/main/kotlin/com/compiler/server/model/Project.kt +++ b/src/main/kotlin/com/compiler/server/model/Project.kt @@ -20,7 +20,9 @@ enum class ProjectType(@JsonValue val id: String) { CANVAS("canvas"), JS_IR("js-ir"), WASM("wasm"), - COMPOSE_WASM("compose-wasm"); + COMPOSE_WASM("compose-wasm"), + SWIFT_EXPORT("swift-export") + ; fun isJvmRelated(): Boolean = this == JAVA || this == JUNIT diff --git a/src/main/kotlin/com/compiler/server/service/KotlinProjectExecutor.kt b/src/main/kotlin/com/compiler/server/service/KotlinProjectExecutor.kt index 327cf4266..3e93d2e14 100644 --- a/src/main/kotlin/com/compiler/server/service/KotlinProjectExecutor.kt +++ b/src/main/kotlin/com/compiler/server/service/KotlinProjectExecutor.kt @@ -17,6 +17,7 @@ class KotlinProjectExecutor( private val completionProvider: CompletionProvider, private val version: VersionInfo, private val kotlinToJSTranslator: KotlinToJSTranslator, + private val swiftExportTranslator: SwiftExportTranslator, private val kotlinEnvironment: KotlinEnvironment, private val loggerDetailsStreamer: LoggerDetailsStreamer? = null, ) { @@ -52,6 +53,10 @@ class KotlinProjectExecutor( return convertWasmWithConverter(project, debugInfo, kotlinToJSTranslator::doTranslateWithWasm) } + fun convertToSwift(project: Project): SwiftExportResult { + return convertSwiftWithConverter(project) + } + fun complete(project: Project, line: Int, character: Int): List { return kotlinEnvironment.environment { val file = getFilesFrom(project, it).first() @@ -76,6 +81,7 @@ class KotlinProjectExecutor( project, debugInfo = false, ).compilerDiagnostics + ProjectType.SWIFT_EXPORT -> convertToSwift(project).compilerDiagnostics } } catch (e: Exception) { log.warn("Exception in getting highlight. Project: $project", e) @@ -114,6 +120,15 @@ class KotlinProjectExecutor( }.also { logExecutionResult(project, it) } } + private fun convertSwiftWithConverter( + project: Project, + ): SwiftExportResult { + return kotlinEnvironment.environment { environment -> + val files = getFilesFrom(project, environment).map { it.kotlinFile } + swiftExportTranslator.translate(files) + }.also { logExecutionResult(project, it) } + } + private fun logExecutionResult(project: Project, executionResult: ExecutionResult) { loggerDetailsStreamer?.logExecutionResult( executionResult, diff --git a/src/test/kotlin/com/compiler/server/SwiftConverterTest.kt b/src/test/kotlin/com/compiler/server/SwiftConverterTest.kt new file mode 100644 index 000000000..d5019d969 --- /dev/null +++ b/src/test/kotlin/com/compiler/server/SwiftConverterTest.kt @@ -0,0 +1,99 @@ +package com.compiler.server + +import com.compiler.server.base.BaseExecutorTest +import org.junit.jupiter.api.Test +import kotlin.test.assertContains +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +class SwiftConverterTest : BaseExecutorTest() { + + private fun exactTest(input: String, expected: String) { + val actual = translateToSwift(input) + assertEquals(expected, actual.swiftCode.trimEnd()) + } + + private fun containsTest(input: String, expected: String) { + val actual = translateToSwift(input) + assertContains(actual.swiftCode.trimEnd(), expected) + } + + private fun shouldFailTest(input: String) { + val actual = translateToSwift(input) + assertTrue(actual.hasErrors()) + } + + @Test + fun basicSwiftExportTest() = containsTest( + input = """ + fun main() {} + """.trimIndent(), + expected = "public func main() -> Swift.Void" + ) + + @Test + fun `use stdlib declaration`() = containsTest( + input = "fun foo(): UInt = 42", + expected = """ + public func foo() -> Swift.UInt32 { + fatalError() + } + """.trimIndent() + ) + + @Test + fun `class declaration`() = exactTest( + input = "public class MyClass { public fun A() {}}", + expected = """ + import KotlinRuntime + + public class MyClass : KotlinRuntime.KotlinBase { + public override init() { + fatalError() + } + public func A() -> Swift.Void { + fatalError() + } + } + """.trimIndent() + ) + + @Test + fun `simple packages`() = exactTest( + input = """ + package foo.bar + + val myProperty: Int = 42 + """.trimIndent(), + expected = """ + public extension Playground.foo.bar { + public static var myProperty: Swift.Int32 { + get { + fatalError() + } + } + } + public enum foo { + public enum bar { + } + } + """.trimIndent() + ) + + @Test + fun `invalid code`() = exactTest( + input = "abracadabra", + expected = """ + """.trimIndent() + ) + + @Test + fun `more invalid code`() = exactTest( + input = "fun foo(): Bar = error()", + expected = """ + public func foo() -> ERROR_TYPE { + fatalError() + } + """.trimIndent() + ) +} \ No newline at end of file diff --git a/src/test/kotlin/com/compiler/server/base/BaseExecutorTest.kt b/src/test/kotlin/com/compiler/server/base/BaseExecutorTest.kt index 6ce60c7af..6ec2adeb8 100644 --- a/src/test/kotlin/com/compiler/server/base/BaseExecutorTest.kt +++ b/src/test/kotlin/com/compiler/server/base/BaseExecutorTest.kt @@ -60,6 +60,8 @@ class BaseExecutorTest { fun translateToJsIr(code: String) = testRunner.translateToJsIr(code) + fun translateToSwift(code: String) = testRunner.translateToSwift(code) + fun runWithException(code: String, contains: String, message: String? = null) = testRunner.runWithException(code, contains, message) fun version() = testRunner.getVersion() diff --git a/src/test/kotlin/com/compiler/server/generator/TestProjectRunner.kt b/src/test/kotlin/com/compiler/server/generator/TestProjectRunner.kt index ec35e598d..dffb0882a 100644 --- a/src/test/kotlin/com/compiler/server/generator/TestProjectRunner.kt +++ b/src/test/kotlin/com/compiler/server/generator/TestProjectRunner.kt @@ -63,6 +63,11 @@ class TestProjectRunner { ) } + fun translateToSwift(code: String): SwiftExportResult { + val project = generateSingleProject(text = code, projectType = ProjectType.SWIFT_EXPORT) + return kotlinProjectExecutor.convertToSwift(project) + } + fun runWithException(code: String, contains: String, message: String? = null): ExecutionResult { val project = generateSingleProject(text = code) val result = kotlinProjectExecutor.run(project) diff --git a/swift-export-playground/README.md b/swift-export-playground/README.md new file mode 100644 index 000000000..c26b5951d --- /dev/null +++ b/swift-export-playground/README.md @@ -0,0 +1 @@ +An implementation of Swift export for Kotlin Playground. \ No newline at end of file diff --git a/swift-export-playground/build.gradle.kts b/swift-export-playground/build.gradle.kts new file mode 100644 index 000000000..134130e28 --- /dev/null +++ b/swift-export-playground/build.gradle.kts @@ -0,0 +1,36 @@ +plugins { + kotlin("jvm") +} + +repositories { + mavenCentral() + // For Analysis API components + maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/kotlin-ide-plugin-dependencies") + maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/swift-export-experimental") +} + +val kotlinVersion = rootProject.properties["systemProp.kotlinVersion"] +val swiftExportVersion = rootProject.properties["systemProp.swiftExportVersion"] + +dependencies { + implementation("org.jetbrains.kotlin:kotlin-compiler:$kotlinVersion") + // For K/N Distribution class + implementation("org.jetbrains.kotlin:kotlin-native-utils:$kotlinVersion") + + // Analysis API components which are required for the Swift export + implementation("org.jetbrains.kotlin:analysis-api-standalone-for-ide:$kotlinVersion") { isTransitive = false } + implementation("org.jetbrains.kotlin:high-level-api-for-ide:$kotlinVersion") { isTransitive = false } + implementation("org.jetbrains.kotlin:high-level-api-fir-for-ide:$kotlinVersion") { isTransitive = false } + implementation("org.jetbrains.kotlin:high-level-api-impl-base-for-ide:$kotlinVersion") { isTransitive = false } + implementation("org.jetbrains.kotlin:low-level-api-fir-for-ide:$kotlinVersion") { isTransitive = false } + implementation("org.jetbrains.kotlin:symbol-light-classes-for-ide:$kotlinVersion") { isTransitive = false } + + // Swift export not-yet-published dependencies. + implementation("org.jetbrains.kotlin:sir:$swiftExportVersion") { isTransitive = false } + implementation("org.jetbrains.kotlin:sir-providers:$swiftExportVersion") { isTransitive = false } + implementation("org.jetbrains.kotlin:sir-light-classes:$swiftExportVersion") { isTransitive = false } + implementation("org.jetbrains.kotlin:sir-printer:$swiftExportVersion") { isTransitive = false } + + testImplementation("junit:junit:4.13.2") + testImplementation("org.jetbrains.kotlin:kotlin-test:$kotlinVersion") +} \ No newline at end of file diff --git a/swift-export-playground/src/main/kotlin/PlaygroundSirSession.kt b/swift-export-playground/src/main/kotlin/PlaygroundSirSession.kt new file mode 100644 index 000000000..cc603c349 --- /dev/null +++ b/swift-export-playground/src/main/kotlin/PlaygroundSirSession.kt @@ -0,0 +1,31 @@ +import org.jetbrains.kotlin.analysis.project.structure.KtModule +import org.jetbrains.kotlin.sir.providers.SirSession +import org.jetbrains.kotlin.sir.providers.SirTypeProvider +import org.jetbrains.kotlin.sir.providers.impl.* +import org.jetbrains.sir.lightclasses.SirDeclarationFromKtSymbolProvider + +internal class PlaygroundSirSession( + ktModule: KtModule, +) : SirSession { + override val declarationNamer = SirDeclarationNamerImpl() + override val enumGenerator = SirEnumGeneratorImpl() + override val moduleProvider = SirSingleModuleProvider("Playground") + override val declarationProvider = CachingSirDeclarationProvider( + declarationsProvider = SirDeclarationFromKtSymbolProvider( + ktModule = ktModule, + sirSession = sirSession, + ) + ) + override val parentProvider = SirParentProviderImpl( + sirSession = sirSession, + ) + override val typeProvider = SirTypeProviderImpl( + errorTypeStrategy = SirTypeProvider.ErrorTypeStrategy.ErrorType, + unsupportedTypeStrategy = SirTypeProvider.ErrorTypeStrategy.ErrorType, + sirSession = sirSession, + ) + override val visibilityChecker = SirVisibilityCheckerImpl() + override val childrenProvider = SirDeclarationChildrenProviderImpl( + sirSession = sirSession, + ) +} \ No newline at end of file diff --git a/swift-export-playground/src/main/kotlin/Runner.kt b/swift-export-playground/src/main/kotlin/Runner.kt new file mode 100644 index 000000000..c74b0f0a9 --- /dev/null +++ b/swift-export-playground/src/main/kotlin/Runner.kt @@ -0,0 +1,81 @@ +import org.jetbrains.kotlin.analysis.api.KtAnalysisApiInternals +import org.jetbrains.kotlin.analysis.api.analyze +import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeTokenProvider +import org.jetbrains.kotlin.analysis.api.standalone.KtAlwaysAccessibleLifetimeTokenProvider +import org.jetbrains.kotlin.analysis.api.standalone.buildStandaloneAnalysisAPISession +import org.jetbrains.kotlin.analysis.project.structure.KtModule +import org.jetbrains.kotlin.analysis.project.structure.builder.buildKtLibraryModule +import org.jetbrains.kotlin.analysis.project.structure.builder.buildKtSourceModule +import org.jetbrains.kotlin.platform.konan.NativePlatforms +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.sir.SirModule +import org.jetbrains.kotlin.sir.SirMutableDeclarationContainer +import org.jetbrains.kotlin.sir.util.addChild +import org.jetbrains.sir.printer.SirAsSwiftSourcesPrinter +import java.nio.file.Path + +/** + * Translate public API of the given [sourceFile] to Swift. + * [stdlibPath] is a path to stdlib.klib which is required to properly resolve references from [sourceFile]. + */ +fun runSwiftExport( + sourceFile: Path, + stdlibPath: Path? +): String { + val (ktModule, sources) = collectModuleAndSources(sourceFile, "Playground", stdlibPath) + + return analyze(ktModule) { + val sirSession = PlaygroundSirSession(ktModule) + val sirModule: SirModule = with(sirSession) { + ktModule.sirModule().also { + sources.flatMap { file -> + file.getFileSymbol().getFileScope().extractDeclarations(analysisSession) + }.forEach { topLevelDeclaration -> + val parent = topLevelDeclaration.parent as? SirMutableDeclarationContainer + ?: error("top level declaration can contain only module or extension to package as a parent") + parent.addChild { topLevelDeclaration } + } + } + } + SirAsSwiftSourcesPrinter.print(sirModule, stableDeclarationsOrder = true, renderDocComments = true) + } +} + +@OptIn(KtAnalysisApiInternals::class) +private fun collectModuleAndSources( + sourceRoot: Path, + kotlinModuleName: String, + stdlibPath: Path?, +): Pair> { + val analysisAPISession = buildStandaloneAnalysisAPISession { + registerProjectService(KtLifetimeTokenProvider::class.java, KtAlwaysAccessibleLifetimeTokenProvider()) + + buildKtModuleProvider { + platform = NativePlatforms.unspecifiedNativePlatform + + val stdlib = stdlibPath?.let { + addModule( + buildKtLibraryModule { + addBinaryRoot(it) + platform = NativePlatforms.unspecifiedNativePlatform + libraryName = "stdlib" + } + ) + } + + addModule( + buildKtSourceModule { + addSourceRoot(sourceRoot) + platform = NativePlatforms.unspecifiedNativePlatform + moduleName = kotlinModuleName + if (stdlib != null) { + addRegularDependency(stdlib) + } + } + ) + } + } + + val (sourceModule, rawFiles) = analysisAPISession.modulesWithFiles.entries.single() + return sourceModule to rawFiles.filterIsInstance() +} \ No newline at end of file diff --git a/swift-export-playground/src/test/kotlin/Tests.kt b/swift-export-playground/src/test/kotlin/Tests.kt new file mode 100644 index 000000000..b7100ffb8 --- /dev/null +++ b/swift-export-playground/src/test/kotlin/Tests.kt @@ -0,0 +1,81 @@ +import kotlin.io.path.* +import kotlin.test.Test +import kotlin.test.assertEquals + +class SwiftExportTests { + + private fun testSources(input: String, expect: String) { + val tempDir = createTempDirectory() + + val inputFormatted = input.trimIndent().trimEnd() + + val inputFile = (tempDir / "input.kt").also { it.writeText(inputFormatted) } + + val actual = runSwiftExport( + sourceFile = inputFile, + stdlibPath = null, + ) + val expectFormatted = expect.trimIndent().trimEnd() + + assertEquals(expectFormatted, actual) + } + + @Test + fun smoke() = testSources( + """ + fun foo(): Int = 5 + """, + """ + public func foo() -> Swift.Int32 { + fatalError() + } + """ + ) + + @Test + fun `class declaration`() = testSources( + """ + class A + """.trimIndent(), + """ + import KotlinRuntime + + public class A : KotlinRuntime.KotlinBase { + public override init() { + fatalError() + } + } + """.trimIndent() + ) + + @Test + fun `object declaration`() = testSources( + """ + object O + """.trimIndent(), + """ + import KotlinRuntime + + public class O : KotlinRuntime.KotlinBase { + public static var shared: Playground.O { + get { + fatalError() + } + } + private override init() { + fatalError() + } + } + """.trimIndent() + ) + + @Test + fun `typealias to basic type declaration`() = testSources( + """ + typealias MyInt = Int + """.trimIndent(), + """ + public typealias MyInt = Swift.Int32 + """.trimIndent() + ) +} \ No newline at end of file From 779ccae0a5d8d0005311f74c67e1605dfa737f75 Mon Sep 17 00:00:00 2001 From: Sergey Bogolepov Date: Tue, 14 May 2024 17:12:15 +0300 Subject: [PATCH 2/4] Update to the latest Swift export version --- gradle.properties | 2 +- .../kotlin/com/compiler/server/SwiftConverterTest.kt | 10 +++++----- swift-export-playground/src/main/kotlin/Runner.kt | 10 +++++++++- swift-export-playground/src/test/kotlin/Tests.kt | 8 ++++---- 4 files changed, 19 insertions(+), 11 deletions(-) diff --git a/gradle.properties b/gradle.properties index 1886fee40..8f5beb2de 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,7 @@ systemProp.kotlinVersion=2.0.0-RC3 systemProp.kotlinIdeVersion=1.9.20-506 systemProp.kotlinIdeVersionSuffix=IJ8109.175 -systemProp.swiftExportVersion=2.0.20-dev-3080 +systemProp.swiftExportVersion=2.0.20-dev-3623 systemProp.policy=executor.policy systemProp.indexes=indexes.json systemProp.indexesJs=indexesJs.json diff --git a/src/test/kotlin/com/compiler/server/SwiftConverterTest.kt b/src/test/kotlin/com/compiler/server/SwiftConverterTest.kt index d5019d969..f58d285e9 100644 --- a/src/test/kotlin/com/compiler/server/SwiftConverterTest.kt +++ b/src/test/kotlin/com/compiler/server/SwiftConverterTest.kt @@ -36,7 +36,7 @@ class SwiftConverterTest : BaseExecutorTest() { input = "fun foo(): UInt = 42", expected = """ public func foo() -> Swift.UInt32 { - fatalError() + stub() } """.trimIndent() ) @@ -49,10 +49,10 @@ class SwiftConverterTest : BaseExecutorTest() { public class MyClass : KotlinRuntime.KotlinBase { public override init() { - fatalError() + stub() } public func A() -> Swift.Void { - fatalError() + stub() } } """.trimIndent() @@ -69,7 +69,7 @@ class SwiftConverterTest : BaseExecutorTest() { public extension Playground.foo.bar { public static var myProperty: Swift.Int32 { get { - fatalError() + stub() } } } @@ -92,7 +92,7 @@ class SwiftConverterTest : BaseExecutorTest() { input = "fun foo(): Bar = error()", expected = """ public func foo() -> ERROR_TYPE { - fatalError() + stub() } """.trimIndent() ) diff --git a/swift-export-playground/src/main/kotlin/Runner.kt b/swift-export-playground/src/main/kotlin/Runner.kt index c74b0f0a9..94cf70a07 100644 --- a/swift-export-playground/src/main/kotlin/Runner.kt +++ b/swift-export-playground/src/main/kotlin/Runner.kt @@ -8,6 +8,7 @@ import org.jetbrains.kotlin.analysis.project.structure.builder.buildKtLibraryMod import org.jetbrains.kotlin.analysis.project.structure.builder.buildKtSourceModule import org.jetbrains.kotlin.platform.konan.NativePlatforms import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.sir.SirFunctionBody import org.jetbrains.kotlin.sir.SirModule import org.jetbrains.kotlin.sir.SirMutableDeclarationContainer import org.jetbrains.kotlin.sir.util.addChild @@ -37,7 +38,14 @@ fun runSwiftExport( } } } - SirAsSwiftSourcesPrinter.print(sirModule, stableDeclarationsOrder = true, renderDocComments = true) + SirAsSwiftSourcesPrinter.print( + sirModule, + stableDeclarationsOrder = true, + renderDocComments = true, + emptyBodyStub = SirFunctionBody( + listOf("stub()") + ) + ) } } diff --git a/swift-export-playground/src/test/kotlin/Tests.kt b/swift-export-playground/src/test/kotlin/Tests.kt index b7100ffb8..ccd6e9215 100644 --- a/swift-export-playground/src/test/kotlin/Tests.kt +++ b/swift-export-playground/src/test/kotlin/Tests.kt @@ -27,7 +27,7 @@ class SwiftExportTests { """, """ public func foo() -> Swift.Int32 { - fatalError() + stub() } """ ) @@ -42,7 +42,7 @@ class SwiftExportTests { public class A : KotlinRuntime.KotlinBase { public override init() { - fatalError() + stub() } } """.trimIndent() @@ -59,11 +59,11 @@ class SwiftExportTests { public class O : KotlinRuntime.KotlinBase { public static var shared: Playground.O { get { - fatalError() + stub() } } private override init() { - fatalError() + stub() } } """.trimIndent() From a49ae3d0f4c20b92ead34437e5b09d49c9f266a4 Mon Sep 17 00:00:00 2001 From: Nikolay Pachkov Date: Thu, 16 May 2024 22:19:57 +0200 Subject: [PATCH 3/4] fix: swift export name --- .../com/compiler/server/controllers/CompilerRestController.kt | 2 +- .../com/compiler/server/model/KotlinTranslatableCompiler.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/com/compiler/server/controllers/CompilerRestController.kt b/src/main/kotlin/com/compiler/server/controllers/CompilerRestController.kt index 67c1e87c4..03cb83543 100644 --- a/src/main/kotlin/com/compiler/server/controllers/CompilerRestController.kt +++ b/src/main/kotlin/com/compiler/server/controllers/CompilerRestController.kt @@ -28,7 +28,7 @@ class CompilerRestController(private val kotlinProjectExecutor: KotlinProjectExe KotlinTranslatableCompiler.JS -> kotlinProjectExecutor.convertToJsIr(project) KotlinTranslatableCompiler.WASM -> kotlinProjectExecutor.convertToWasm(project, debugInfo) KotlinTranslatableCompiler.COMPOSE_WASM -> kotlinProjectExecutor.convertToWasm(project, debugInfo) - KotlinTranslatableCompiler.SWIFT -> kotlinProjectExecutor.convertToSwift(project).let { + KotlinTranslatableCompiler.SWIFT_EXPORT -> kotlinProjectExecutor.convertToSwift(project).let { // TODO: A hack to avoid changing the return type of the function. object : TranslationResultWithJsCode(it.swiftCode, it.compilerDiagnostics, it.exception) {} } diff --git a/src/main/kotlin/com/compiler/server/model/KotlinTranslatableCompiler.kt b/src/main/kotlin/com/compiler/server/model/KotlinTranslatableCompiler.kt index 4bc2dc8c5..bdeb29012 100644 --- a/src/main/kotlin/com/compiler/server/model/KotlinTranslatableCompiler.kt +++ b/src/main/kotlin/com/compiler/server/model/KotlinTranslatableCompiler.kt @@ -4,5 +4,5 @@ enum class KotlinTranslatableCompiler { JS, WASM, COMPOSE_WASM, - SWIFT, + SWIFT_EXPORT, } \ No newline at end of file From 9dbe660a7a2466212c9072a4a8fb7e1a858fcd6b Mon Sep 17 00:00:00 2001 From: nikpachoo Date: Fri, 17 May 2024 14:31:21 +0200 Subject: [PATCH 4/4] Swift export: rollback to 2.0.0-RC2 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 8f5beb2de..4a7878eb7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -systemProp.kotlinVersion=2.0.0-RC3 +systemProp.kotlinVersion=2.0.0-RC2 systemProp.kotlinIdeVersion=1.9.20-506 systemProp.kotlinIdeVersionSuffix=IJ8109.175 systemProp.swiftExportVersion=2.0.20-dev-3623