[JS IR] Add work around in EnumEntriesList for JS IR to avoid name clashes

JS IR generates bridges with type checks for special class methods,
 however if parent and child type parameters are same,
 the JS signature for the generated brige will be clashed with
 the JS signature of original method.

 This patch changes type parameter name of EnumEntriesList to avoid the clash.

^KT-54011 Fixed
This commit is contained in:
Alexander Korepanov
2022-09-13 13:26:47 +02:00
committed by Space
parent 639af77b91
commit 47bbd5e8c1
13 changed files with 130 additions and 14 deletions
@@ -16,6 +16,8 @@ import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.ir.backend.js.*
import org.jetbrains.kotlin.ir.backend.js.ic.*
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsIrLinker
@@ -31,6 +33,7 @@ import org.jetbrains.kotlin.js.testOld.V8IrJsTestChecker
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.serialization.js.ModuleKind
import org.jetbrains.kotlin.test.builders.LanguageVersionSettingsBuilder
import org.jetbrains.kotlin.test.KotlinTestWithEnvironment
import org.jetbrains.kotlin.test.util.JUnit4Assertions
import org.junit.ComparisonFailure
@@ -93,11 +96,24 @@ abstract class AbstractInvalidationTest : KotlinTestWithEnvironment() {
return File(File(buildDir, moduleName), "cache")
}
private fun createConfiguration(moduleName: String): CompilerConfiguration {
private fun createConfiguration(moduleName: String, language: List<String>): CompilerConfiguration {
val copy = environment.configuration.copy()
copy.put(CommonConfigurationKeys.MODULE_NAME, moduleName)
copy.put(JSConfigurationKeys.MODULE_KIND, ModuleKind.PLAIN)
copy.put(JSConfigurationKeys.PROPERTY_LAZY_INITIALIZATION, true)
copy.languageVersionSettings = with(LanguageVersionSettingsBuilder()) {
language.forEach {
val switchLanguageFeature = when {
it.startsWith("+") -> this::enable
it.startsWith("-") -> this::disable
else -> error("Language feature should start with + or -")
}
val feature = LanguageFeature.fromString(it.substring(1)) ?: error("Unknown language feature $it")
switchLanguageFeature(feature)
}
build()
}
return copy
}
@@ -115,7 +131,8 @@ abstract class AbstractInvalidationTest : KotlinTestWithEnvironment() {
val expectedFileStats: Map<String, Set<String>>
)
private fun setupTestStep(projStepId: Int, module: String): TestStepInfo {
private fun setupTestStep(projStep: ProjectInfo.ProjectBuildStep, module: String): TestStepInfo {
val projStepId = projStep.id
val moduleTestDir = File(testDir, module)
val moduleSourceDir = File(sourceDir, module)
val moduleInfo = moduleInfos[module] ?: error("No module info found for $module")
@@ -127,7 +144,7 @@ abstract class AbstractInvalidationTest : KotlinTestWithEnvironment() {
val dependencies = moduleStep.dependencies.mapTo(mutableListOf(File(STDLIB_KLIB))) { resolveModuleArtifact(it, buildDir) }
val outputKlibFile = resolveModuleArtifact(module, buildDir)
val configuration = createConfiguration(module)
val configuration = createConfiguration(module, projStep.language)
buildArtifact(configuration, module, moduleSourceDir, dependencies, outputKlibFile)
val expectedFileStats = if (deletedFiles.isEmpty()) {
@@ -232,9 +249,9 @@ abstract class AbstractInvalidationTest : KotlinTestWithEnvironment() {
fun execute() {
val stdlibCacheDir = resolveModuleCache(STDLIB_ALIAS, buildDir).canonicalPath
for (projStep in projectInfo.steps) {
val testInfo = projStep.order.map { setupTestStep(projStep.id, it) }
val testInfo = projStep.order.map { setupTestStep(projStep, it) }
val configuration = createConfiguration(projStep.order.last())
val configuration = createConfiguration(projStep.order.last(), projStep.language)
val cacheUpdater = CacheUpdater(
mainModule = testInfo.last().modulePath,
allModules = testInfo.mapTo(mutableListOf(STDLIB_KLIB)) { it.modulePath },
@@ -75,6 +75,11 @@ public class InvalidationTestGenerated extends AbstractInvalidationTest {
runTest("js/js.translator/testData/incremental/invalidation/eagerInitialization/");
}
@TestMetadata("enum")
public void testEnum() throws Exception {
runTest("js/js.translator/testData/incremental/invalidation/enum/");
}
@TestMetadata("exportsThroughInlineFunction")
public void testExportsThroughInlineFunction() throws Exception {
runTest("js/js.translator/testData/incremental/invalidation/exportsThroughInlineFunction/");
@@ -0,0 +1 @@
enum class TestEnum
@@ -0,0 +1,3 @@
enum class TestEnum {
A, B
}
@@ -0,0 +1,12 @@
STEP 0:
modifications:
U : l1.0.kt -> l1.kt
added file: l1.kt
STEP 1:
modifications:
U : l1.1.kt -> l1.kt
modified ir: l1.kt
STEP 2:
modified config: l1.kt
STEP 3:
updated exports: l1.kt
@@ -0,0 +1,8 @@
@kotlin.ExperimentalStdlibApi
fun box(stepId: Int): String {
when {
!testEnumValues(stepId) -> return "Fail testEnumValues"
!testEnumEntries(stepId) -> return "Fail testEnumEntries"
}
return "OK"
}
@@ -0,0 +1,15 @@
STEP 0:
modifications:
U : testEnumEntries.0.kt -> testEnumEntries.kt
dependencies: lib1
added file: m.kt, testEnumEntries.kt, testEnumValues.kt
STEP 1:
dependencies: lib1
STEP 2:
dependencies: lib1
modified config: m.kt, testEnumEntries.kt, testEnumValues.kt
STEP 3:
modifications:
U : testEnumEntries.3.kt -> testEnumEntries.kt
dependencies: lib1
modified ir: testEnumEntries.kt
@@ -0,0 +1,4 @@
@kotlin.ExperimentalStdlibApi
fun testEnumEntries(stepId: Int): Boolean {
return true
}
@@ -0,0 +1,18 @@
@kotlin.ExperimentalStdlibApi
fun testEnumEntries(stepId: Int): Boolean {
val entries = TestEnum.entries
if (entries.contains((object {}) as Any?)) return false
when (stepId) {
0 -> if (entries.isNotEmpty()) return false
1, 2, 3 -> {
if (entries.size != 2) return false
if (entries.indexOf(TestEnum.A) != 0) return false
if (entries.indexOf(TestEnum.B) != 1) return false
}
else -> return false
}
return true
}
@@ -0,0 +1,9 @@
fun testEnumValues(stepId: Int): Boolean {
val values = enumValues<TestEnum>().map { it.ordinal to it.name }
when (stepId) {
0 -> if (values.isEmpty()) return true
1, 2, 3 -> if (values == listOf(0 to "A", 1 to "B")) return true
else -> return false
}
return false
}
@@ -0,0 +1,16 @@
MODULES: lib1, main
STEP 0:
libs: lib1, main
dirty js: lib1, main
STEP 1:
libs: lib1, main
dirty js: lib1
STEP 2:
language: +EnumEntries
libs: lib1, main
dirty js: main, lib1
STEP 3:
language: +EnumEntries
libs: lib1, main
dirty js: main, lib1