[JS][Tests] Add test for JS klib resolver
^KT-70146
diff --git a/compiler/util-klib-metadata/src/org/jetbrains/kotlin/library/metadata/resolver/impl/KotlinLibraryResolverImpl.kt b/compiler/util-klib-metadata/src/org/jetbrains/kotlin/library/metadata/resolver/impl/KotlinLibraryResolverImpl.kt
index 6853f41..be6c4e8 100644
--- a/compiler/util-klib-metadata/src/org/jetbrains/kotlin/library/metadata/resolver/impl/KotlinLibraryResolverImpl.kt
+++ b/compiler/util-klib-metadata/src/org/jetbrains/kotlin/library/metadata/resolver/impl/KotlinLibraryResolverImpl.kt
@@ -113,7 +113,7 @@
var newDependencies = rootLibraries
do {
newDependencies = newDependencies.map { library: KotlinResolvedLibraryImpl ->
- library.library.unresolvedDependencies(lenient = true).asSequence()
+ library.library.unresolvedDependencies(resolveManifestDependenciesLenient).asSequence()
.filterNot { searchPathResolver.isProvidedByDefault(it) }
.mapNotNull { searchPathResolver.resolve(it)?.let(::KotlinResolvedLibraryImpl) }
diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/testOld/klib/JsKlibResolverTest.kt b/js/js.tests/test/org/jetbrains/kotlin/js/testOld/klib/JsKlibResolverTest.kt
index 0d1d646..b766c71 100644
--- a/js/js.tests/test/org/jetbrains/kotlin/js/testOld/klib/JsKlibResolverTest.kt
+++ b/js/js.tests/test/org/jetbrains/kotlin/js/testOld/klib/JsKlibResolverTest.kt
@@ -7,16 +7,29 @@
import org.jetbrains.kotlin.cli.common.ExitCode
import org.jetbrains.kotlin.cli.js.K2JSCompiler
+import org.jetbrains.kotlin.js.config.EcmaVersion
import org.jetbrains.kotlin.test.TestCaseWithTmpdir
import org.jetbrains.kotlin.test.services.StandardLibrariesPathProviderForKotlinProject
import org.jetbrains.kotlin.test.util.JUnit4Assertions
import org.jetbrains.kotlin.test.utils.assertCompilerOutputHasKlibResolverIncompatibleAbiMessages
import org.jetbrains.kotlin.test.utils.patchManifestToBumpAbiVersion
+import org.junit.jupiter.api.DisplayName
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.PrintStream
class JsKlibResolverTest : TestCaseWithTmpdir() {
+ private data class Module(val name: String, val dependencyNames: List<String>) {
+ constructor(name: String, vararg dependencyNames: String) : this(name, dependencyNames.asList())
+
+ lateinit var dependencies: List<Module>
+ lateinit var sourceFile: File
+
+ fun initDependencies(resolveDependency: (String) -> Module) {
+ dependencies = dependencyNames.map(resolveDependency)
+ }
+ }
+
fun testWarningAboutRejectedLibraryIsNotSuppressed() {
val testDataDir = File("compiler/testData/klib/resolve/mismatched-abi-version")
@@ -50,6 +63,34 @@
assertCompilerOutputHasKlibResolverIncompatibleAbiMessages(JUnit4Assertions, result.output, missingLibrary = "/v2/lib1", tmpdir)
}
+ @DisplayName("Test resolving nonexistent transitive dependency recorded in `depends` property (KT-70146)")
+ fun testResolvingTransitiveDependenciesRecordedInManifest() {
+ val moduleA = Module("a")
+ val moduleB = Module("b", "a")
+ val moduleC = Module("c", "b")
+ val modules = createModules(moduleA, moduleB, moduleC)
+
+ println(modules)
+ val aKlib = tmpdir.resolve("a.klib").also { it.mkdirs() }
+ val resultA = compileKlib(moduleA.sourceFile, dependency = null, outputFile = aKlib)
+ assertEquals(ExitCode.OK, resultA.exitCode)
+
+ val bKlib = tmpdir.resolve("b.klib").also { it.mkdirs() }
+ val resultB = compileKlib(moduleB.sourceFile, dependency = aKlib, outputFile = bKlib)
+ assertEquals(ExitCode.OK, resultB.exitCode)
+
+ // remove transitive dependency `a`, to check that subsequent compilation of `c` would not fail,
+ // since resolve on 1-st stage is performed without dependencies
+ aKlib.deleteRecursively()
+ val cKlib = tmpdir.resolve("c.klib").also { it.mkdirs() }
+ val resultC = compileKlib(moduleC.sourceFile, dependency = bKlib, outputFile = cKlib)
+ assertEquals(ExitCode.OK, resultC.exitCode)
+
+ val resultJS = compileToJs(moduleC.sourceFile, dependency = bKlib, outputFile = tmpdir)
+ println(resultJS.output)
+ assertEquals(ExitCode.OK, resultJS.exitCode)
+ }
+
private fun createKlibDir(name: String, version: Int): File =
tmpdir.resolve("v$version").resolve(name).apply(File::mkdirs)
@@ -75,6 +116,29 @@
return CompilationResult(exitCode, compilerXmlOutput.toString())
}
+ private fun compileToJs(sourceFile: File, dependency: File?, outputFile: File): CompilationResult {
+ val libraries = listOfNotNull(
+ StandardLibrariesPathProviderForKotlinProject.fullJsStdlib(),
+ dependency
+ ).joinToString(File.pathSeparator) { it.absolutePath }
+
+ val args = arrayOf(
+ "-Xir-produce-js",
+ "-libraries", libraries,
+ "-ir-output-dir", outputFile.absolutePath,
+ "-ir-output-name", outputFile.nameWithoutExtension,
+ "-target", EcmaVersion.defaultVersion(),
+ sourceFile.absolutePath
+ )
+
+ val compilerXmlOutput = ByteArrayOutputStream()
+ val exitCode = PrintStream(compilerXmlOutput).use { printStream ->
+ K2JSCompiler().execFullPathsInMessages(printStream, args)
+ }
+
+ return CompilationResult(exitCode, compilerXmlOutput.toString())
+ }
+
private data class CompilationResult(val exitCode: ExitCode, val output: String) {
fun assertSuccess() = JUnit4Assertions.assertTrue(exitCode == ExitCode.OK) {
buildString {
@@ -92,4 +156,34 @@
}
}
}
+
+ private fun createModules(vararg modules: Module): List<Module> {
+ val mapping: Map<String, Module> = modules.groupBy(Module::name).mapValues {
+ it.value.singleOrNull() ?: error("Duplicated modules: ${it.value}")
+ }
+
+ modules.forEach { it.initDependencies(mapping::getValue) }
+
+ val generatedSourcesDir = tmpdir.resolve("generated-sources")
+ generatedSourcesDir.mkdirs()
+
+ modules.forEach { module ->
+ module.sourceFile = generatedSourcesDir.resolve(module.name + ".kt")
+ module.sourceFile.writeText(
+ buildString {
+ appendLine("package ${module.name}")
+ appendLine()
+ appendLine("fun ${module.name}(indent: Int) {")
+ appendLine(" repeat(indent) { print(\" \") }")
+ appendLine(" println(\"${module.name}\")")
+ module.dependencyNames.forEach { dependencyName ->
+ appendLine(" $dependencyName.$dependencyName(indent + 1)")
+ }
+ appendLine("}")
+ }
+ )
+ }
+
+ return modules.asList()
+ }
}
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt
index 670148f..5f08471 100644
--- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt
+++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt
@@ -296,7 +296,7 @@
get() = configuration.getBoolean(KonanConfigKeys.PURGE_USER_LIBS)
internal val resolve = KonanLibrariesResolveSupport(
- configuration, target, distribution, resolveManifestDependenciesLenient = metadataKlib
+ configuration, target, distribution, resolveManifestDependenciesLenient = true
)
val resolvedLibraries get() = resolve.resolvedLibraries