JVM_IR: Add test for compiling against cross-platform Klib

This commit is contained in:
Georgy Bronnikov
2019-11-26 17:53:00 +03:00
parent f1b5198b86
commit 8f4b4007fe
16 changed files with 235 additions and 7 deletions
+1
View File
@@ -12,6 +12,7 @@
<list> <list>
<option value=":compiler:generateTests" /> <option value=":compiler:generateTests" />
<option value=":compiler:tests-java8:generateTests" /> <option value=":compiler:tests-java8:generateTests" />
<option value=":compiler:tests-against-klib:generateTests" />
<option value=":js:js.tests:generateTests" /> <option value=":js:js.tests:generateTests" />
<option value=":core:descriptors.runtime:generateTests" /> <option value=":core:descriptors.runtime:generateTests" />
</list> </list>
+2 -1
View File
@@ -513,7 +513,8 @@ tasks {
":compiler:test", ":compiler:test",
":compiler:container:test", ":compiler:container:test",
":compiler:tests-java8:test", ":compiler:tests-java8:test",
":compiler:tests-spec:remoteRunTests" ":compiler:tests-spec:remoteRunTests",
":compiler:tests-against-klib:test"
) )
dependsOn(":plugins:jvm-abi-gen:test") dependsOn(":plugins:jvm-abi-gen:test")
} }
+1
View File
@@ -102,6 +102,7 @@ sourceSets {
projectTest(parallel = true) { projectTest(parallel = true) {
dependsOn(":dist") dependsOn(":dist")
workingDir = rootDir workingDir = rootDir
systemProperty("kotlin.test.script.classpath", testSourceSet.output.classesDirs.joinToString(File.pathSeparator)) systemProperty("kotlin.test.script.classpath", testSourceSet.output.classesDirs.joinToString(File.pathSeparator))
doFirst { doFirst {
@@ -302,6 +302,13 @@ class K2JVMCompilerArguments : CommonCompilerArguments() {
) )
var emitJvmTypeAnnotations: Boolean by FreezableVar(false) var emitJvmTypeAnnotations: Boolean by FreezableVar(false)
@Argument(
value = "-Xklib",
valueDescription = "<path>",
description = "Paths to cross-platform libraries in .klib format"
)
val klibLibraries: String? by NullableStringFreezableVar(null)
override fun configureAnalysisFlags(collector: MessageCollector): MutableMap<AnalysisFlag<*>, Any> { override fun configureAnalysisFlags(collector: MessageCollector): MutableMap<AnalysisFlag<*>, Any> {
val result = super.configureAnalysisFlags(collector) val result = super.configureAnalysisFlags(collector)
result[JvmAnalysisFlags.strictMetadataVersionSemantics] = strictMetadataVersionSemantics result[JvmAnalysisFlags.strictMetadataVersionSemantics] = strictMetadataVersionSemantics
@@ -75,6 +75,7 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
configuration.configureExplicitContentRoots(arguments) configuration.configureExplicitContentRoots(arguments)
configuration.configureStandardLibs(paths, arguments) configuration.configureStandardLibs(paths, arguments)
configuration.configureAdvancedJvmOptions(arguments) configuration.configureAdvancedJvmOptions(arguments)
configuration.configureKlibPaths(arguments)
if (arguments.buildFile == null && !arguments.version && !arguments.allowNoSourceFiles && if (arguments.buildFile == null && !arguments.version && !arguments.allowNoSourceFiles &&
(arguments.script || arguments.expression != null || arguments.freeArgs.isEmpty())) { (arguments.script || arguments.expression != null || arguments.freeArgs.isEmpty())) {
@@ -138,7 +138,6 @@ fun KotlinCoreEnvironment.registerJavacIfNeeded(
return true return true
} }
fun CompilerConfiguration.configureAdvancedJvmOptions(arguments: K2JVMCompilerArguments) { fun CompilerConfiguration.configureAdvancedJvmOptions(arguments: K2JVMCompilerArguments) {
put(JVMConfigurationKeys.PARAMETERS_METADATA, arguments.javaParameters) put(JVMConfigurationKeys.PARAMETERS_METADATA, arguments.javaParameters)
@@ -199,3 +198,11 @@ fun CompilerConfiguration.configureAdvancedJvmOptions(arguments: K2JVMCompilerAr
arguments.declarationsOutputPath?.let { put(JVMConfigurationKeys.DECLARATIONS_JSON_PATH, it) } arguments.declarationsOutputPath?.let { put(JVMConfigurationKeys.DECLARATIONS_JSON_PATH, it) }
} }
fun CompilerConfiguration.configureKlibPaths(arguments: K2JVMCompilerArguments) {
assert(arguments.useIR || arguments.klibLibraries == null) { "Klib libraries can only be used with IR backend" }
arguments.klibLibraries?.split(File.pathSeparator.toRegex())
?.toTypedArray()
?.filterNot { it.isEmpty() }
?.let { put(JVMConfigurationKeys.KLIB_PATHS, it) }
}
@@ -113,4 +113,7 @@ public class JVMConfigurationKeys {
public static final CompilerConfigurationKey<Boolean> EMIT_JVM_TYPE_ANNOTATIONS = public static final CompilerConfigurationKey<Boolean> EMIT_JVM_TYPE_ANNOTATIONS =
CompilerConfigurationKey.create("Emit JVM type annotations in bytecode"); CompilerConfigurationKey.create("Emit JVM type annotations in bytecode");
public static final CompilerConfigurationKey<List<String>> KLIB_PATHS =
CompilerConfigurationKey.create("Paths to .klib libraries");
} }
+16
View File
@@ -0,0 +1,16 @@
// FILE: klib.kt
package fromKlib
class C {
val x = "OK"
}
fun foo(): String {
return C().x
}
// FILE: test.kt
import fromKlib.foo
fun box(): String {
return foo()
}
@@ -0,0 +1,30 @@
import org.jetbrains.kotlin.gradle.dsl.KotlinCompile
import java.io.File
plugins {
kotlin("jvm")
id("jps-compatible")
}
dependencies {
compile(kotlinStdlib())
testCompile(projectTests(":compiler:visualizer"))
testCompile(projectTests(":generators:test-generator"))
}
sourceSets {
"main" { }
"test" { projectDefault() }
}
testsJar {}
projectTest(parallel = true) {
dependsOn(":dist")
dependsOn(":kotlin-stdlib-js-ir:generateFullRuntimeKLib")
workingDir = rootDir
systemProperty("kotlin.test.script.classpath", testSourceSet.output.classesDirs.joinToString(File.pathSeparator))
}
val generateTests by generator("org.jetbrains.kotlin.generators.tests.GenerateCompilerTestsAgainstKlibKt")
@@ -0,0 +1,95 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.codegen.ir
import org.jetbrains.kotlin.cli.AbstractCliTest
import org.jetbrains.kotlin.cli.common.ExitCode
import org.jetbrains.kotlin.cli.js.K2JSCompiler
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment.Companion.createForTests
import org.jetbrains.kotlin.codegen.AbstractBlackBoxCodegenTest
import org.jetbrains.kotlin.codegen.CodegenTestCase
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.kotlin.test.TargetBackend
import org.jetbrains.kotlin.utils.rethrow
import java.io.File
import java.nio.file.Paths
import java.util.*
import java.util.concurrent.TimeUnit
abstract class AbstractCompileKotlinAgainstKlibTest : AbstractBlackBoxCodegenTest() {
lateinit var klibName: String
lateinit var outputDir: File
override fun getBackend() = TargetBackend.JVM_IR
override fun doMultiFileTest(wholeFile: File, files: List<TestFile>) {
outputDir = javaSourcesOutputDirectory
klibName = Paths.get(outputDir.toString(), wholeFile.name.toString().removeSuffix(".kt")).toString()
val classpath: MutableList<File> = ArrayList()
classpath.add(KotlinTestUtils.getAnnotationsJar())
val configuration = createConfiguration(
configurationKind, CodegenTestCase.getJdkKind(files),
classpath,
listOf(outputDir),
files
)
myEnvironment = createForTests(
testRootDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES
)
setupEnvironment(myEnvironment)
// All files but last are Klib's sources.
try {
compileToKlib(files.dropLast(1))
} catch (t: Throwable) {
if (!isIgnoredTarget(wholeFile)) {
throw t
}
}
super.doMultiFileTest(wholeFile, listOf(files.last()))
}
override fun updateConfiguration(configuration: CompilerConfiguration) {
configuration.put(JVMConfigurationKeys.KLIB_PATHS, listOf(klibName + ".klib"))
}
// We need real (as opposed to virtual) files in order to produce a Klib.
private fun loadMultiFilesReal(files: List<TestFile>): List<String> {
val dir = outputDir
return files.map { testFile ->
assert(testFile.name.endsWith(".kt"))
val ktFile = File(Paths.get(dir.toString(), testFile.name).toString())
ktFile.writeText(testFile.content)
ktFile.toString()
}
}
// For now, while there is no common backend, we generate Klib using
// the JS_IR compiler.
private fun compileToKlib(files: List<TestFile>) {
val sourceFiles = loadMultiFilesReal(files)
val (output, exitCode) = AbstractCliTest.executeCompilerGrabOutput(
K2JSCompiler(),
listOf(
"-output", klibName,
"-Xir-produce-klib-file",
"-libraries", "libraries/stdlib/js-ir/build/fullRuntime/klib/"
) + sourceFiles
)
if (exitCode != ExitCode.OK) {
throw Exception(output)
}
}
companion object {
const val TIMEOUT_SECONDS = 10L
}
}
@@ -0,0 +1,36 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.codegen.ir;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
import org.jetbrains.kotlin.test.KotlinTestUtils;
import org.jetbrains.kotlin.test.TargetBackend;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.runner.RunWith;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("compiler/testData/codegen/boxKlib")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public class CompileKotlinAgainstKlibTestGenerated extends AbstractCompileKotlinAgainstKlibTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM_IR, testDataFilePath);
}
public void testAllFilesPresentInBoxKlib() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxKlib"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("compiler/testData/codegen/boxKlib/simple.kt");
}
}
@@ -0,0 +1,20 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.generators.tests
import org.jetbrains.kotlin.codegen.ir.*
import org.jetbrains.kotlin.generators.tests.generator.testGroup
import org.jetbrains.kotlin.test.TargetBackend
fun main(args: Array<String>) {
System.setProperty("java.awt.headless", "true")
testGroup("compiler/tests-against-klib/tests", "compiler/testData") {
testClass<AbstractCompileKotlinAgainstKlibTest> {
model("codegen/boxKlib", targetBackend = TargetBackend.JVM_IR)
}
}
}
@@ -15,7 +15,6 @@ import org.jetbrains.kotlin.codegen.ir.AbstractFirBlackBoxCodegenTest;
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil; import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil;
import org.jetbrains.kotlin.psi.KtFile; import org.jetbrains.kotlin.psi.KtFile;
import org.jetbrains.kotlin.test.InTextDirectivesUtils; import org.jetbrains.kotlin.test.InTextDirectivesUtils;
import org.jetbrains.kotlin.test.TargetBackend;
import org.jetbrains.kotlin.utils.ExceptionUtilsKt; import org.jetbrains.kotlin.utils.ExceptionUtilsKt;
import java.io.File; import java.io.File;
@@ -33,9 +32,7 @@ public abstract class AbstractBlackBoxCodegenTest extends CodegenTestCase {
@NotNull List<TestFile> files, @NotNull List<TestFile> files,
boolean unexpectedBehaviour boolean unexpectedBehaviour
) throws Exception { ) throws Exception {
boolean isIgnored = InTextDirectivesUtils.isIgnoredTarget(getBackend(), wholeFile) || boolean isIgnored = isIgnoredTarget(wholeFile);
(this instanceof AbstractFirBlackBoxCodegenTest &&
InTextDirectivesUtils.isDirectiveDefined(FileUtil.loadFile(wholeFile), "IGNORE_BACKEND_FIR: JVM_IR"));
compile(files, !isIgnored, false); compile(files, !isIgnored, false);
@@ -142,4 +139,15 @@ public abstract class AbstractBlackBoxCodegenTest extends CodegenTestCase {
? null ? null
: JvmFileClassUtil.getFileClassInfoNoResolve(file).getFacadeClassFqName().asString(); : JvmFileClassUtil.getFileClassInfoNoResolve(file).getFacadeClassFqName().asString();
} }
protected boolean isIgnoredTarget(@NotNull File wholeFile) {
try {
return InTextDirectivesUtils.isIgnoredTarget(getBackend(), wholeFile) ||
(this instanceof AbstractFirBlackBoxCodegenTest &&
InTextDirectivesUtils.isDirectiveDefined(FileUtil.loadFile(wholeFile), "IGNORE_BACKEND_FIR: JVM_IR"));
}
catch (Exception e) {
throw ExceptionUtilsKt.rethrow(e);
}
}
} }
@@ -513,7 +513,6 @@ fun main(args: Array<String>) {
} }
} }
testGroup("compiler/fir/psi2fir/tests", "compiler/fir/psi2fir/testData") { testGroup("compiler/fir/psi2fir/tests", "compiler/fir/psi2fir/testData") {
testClass<AbstractRawFirBuilderTestCase> { testClass<AbstractRawFirBuilderTestCase> {
model("rawBuilder", testMethod = "doRawFirTest") model("rawBuilder", testMethod = "doRawFirTest")
@@ -181,6 +181,8 @@ private fun CompilerConfiguration.updateWithCompilerOptions(
setupJvmSpecificArguments(compilerArguments) setupJvmSpecificArguments(compilerArguments)
configureAdvancedJvmOptions(compilerArguments) configureAdvancedJvmOptions(compilerArguments)
configureKlibPaths(compilerArguments)
} }
private fun ScriptCompilationConfiguration.withUpdatesFromCompilerConfiguration(kotlinCompilerConfiguration: CompilerConfiguration) = private fun ScriptCompilationConfiguration.withUpdatesFromCompilerConfiguration(kotlinCompilerConfiguration: CompilerConfiguration) =
+1
View File
@@ -114,6 +114,7 @@ include ":kotlin-build-common",
":compiler:android-tests", ":compiler:android-tests",
":compiler:tests-common", ":compiler:tests-common",
":compiler:tests-common-jvm6", ":compiler:tests-common-jvm6",
":compiler:tests-against-klib",
":dukat", ":dukat",
":js:js.ast", ":js:js.ast",
":js:js.serializer", ":js:js.serializer",