diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt index bcca78b36dd..a925a3ac1ac 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt @@ -359,6 +359,8 @@ class GenerationState private constructor( else null + val oldInnerClassesLogic = configuration.getBoolean(JVMConfigurationKeys.OLD_INNER_CLASSES_LOGIC) + init { this.interceptedBuilderFactory = builderFactory .wrapWith( diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.kt b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.kt index 0df0a51f2cd..6607efdd88f 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.kt +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.kt @@ -527,6 +527,12 @@ Also sets `-jvm-target` value equal to the selected JDK version""" ) var noNewJavaAnnotationTargets: Boolean by FreezableVar(false) + @Argument( + value = "-Xuse-old-innerclasses-logic", + description = "Use old logic for generation of InnerClasses attributes" + ) + var oldInnerClassesLogic: Boolean by FreezableVar(false) + override fun configureAnalysisFlags(collector: MessageCollector, languageVersion: LanguageVersion): MutableMap, Any> { val result = super.configureAnalysisFlags(collector, languageVersion) result[JvmAnalysisFlags.strictMetadataVersionSemantics] = strictMetadataVersionSemantics diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/jvmArguments.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/jvmArguments.kt index 92a55de4157..39014d728fd 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/jvmArguments.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/jvmArguments.kt @@ -318,6 +318,7 @@ fun CompilerConfiguration.configureAdvancedJvmOptions(arguments: K2JVMCompilerAr put(JVMConfigurationKeys.ENABLE_DEBUG_MODE, arguments.enableDebugMode) put(JVMConfigurationKeys.IGNORE_CONST_OPTIMIZATION_ERRORS, arguments.ignoreConstOptimizationErrors) put(JVMConfigurationKeys.NO_NEW_JAVA_ANNOTATION_TARGETS, arguments.noNewJavaAnnotationTargets) + put(JVMConfigurationKeys.OLD_INNER_CLASSES_LOGIC, arguments.oldInnerClassesLogic) val assertionsMode = JVMAssertionsMode.fromStringOrNull(arguments.assertionsMode) diff --git a/compiler/config.jvm/src/org/jetbrains/kotlin/config/JVMConfigurationKeys.java b/compiler/config.jvm/src/org/jetbrains/kotlin/config/JVMConfigurationKeys.java index f8642829f32..02159f13e58 100644 --- a/compiler/config.jvm/src/org/jetbrains/kotlin/config/JVMConfigurationKeys.java +++ b/compiler/config.jvm/src/org/jetbrains/kotlin/config/JVMConfigurationKeys.java @@ -162,4 +162,7 @@ public class JVMConfigurationKeys { public static final CompilerConfigurationKey NO_NEW_JAVA_ANNOTATION_TARGETS = CompilerConfigurationKey.create("Do not generate Java 1.8+ targets for Kotlin annotation classes"); + + public static final CompilerConfigurationKey OLD_INNER_CLASSES_LOGIC = + CompilerConfigurationKey.create("Use old logic for generation of InnerClasses attributes"); } diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBytecodeTextTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBytecodeTextTestGenerated.java index 960a114903e..480f0f1be33 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBytecodeTextTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBytecodeTextTestGenerated.java @@ -4054,11 +4054,23 @@ public class FirBytecodeTextTestGenerated extends AbstractFirBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/innerClasses/kt27936.kt"); } + @Test + @TestMetadata("kt53804.kt") + public void testKt53804() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/innerClasses/kt53804.kt"); + } + @Test @TestMetadata("nestedClassInAnnotationArgument.kt") public void testNestedClassInAnnotationArgument() throws Exception { runTest("compiler/testData/codegen/bytecodeText/innerClasses/nestedClassInAnnotationArgument.kt"); } + + @Test + @TestMetadata("nestedClassInAnnotationArgumentOldMode.kt") + public void testNestedClassInAnnotationArgumentOldMode() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/innerClasses/nestedClassInAnnotationArgumentOldMode.kt"); + } } @Nested diff --git a/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt b/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt index c18234ac942..3928a18194a 100644 --- a/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt +++ b/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt @@ -87,16 +87,19 @@ class ClassCodegen private constructor( // under incremental compilation, as calls to `inline fun`s declared in this class cause them to be generated out of order. private val innerClasses = linkedSetOf() - val typeMapper = object : IrTypeMapper(context) { - override fun mapType(type: IrType, mode: TypeMappingMode, sw: JvmSignatureWriter?): Type { - var t = type - while (t.isArray()) { - t = t.getArrayElementType(context.irBuiltIns) + val typeMapper = + if (context.state.oldInnerClassesLogic) + context.defaultTypeMapper + else object : IrTypeMapper(context) { + override fun mapType(type: IrType, mode: TypeMappingMode, sw: JvmSignatureWriter?): Type { + var t = type + while (t.isArray()) { + t = t.getArrayElementType(context.irBuiltIns) + } + t.classOrNull?.owner?.let(::addInnerClassInfo) + return super.mapType(type, mode, sw) } - t.classOrNull?.owner?.let(::addInnerClassInfo) - return super.mapType(type, mode, sw) } - } val methodSignatureMapper = MethodSignatureMapper(context, typeMapper) diff --git a/compiler/test-infrastructure/tests/org/jetbrains/kotlin/test/directives/LanguageSettingsDirectives.kt b/compiler/test-infrastructure/tests/org/jetbrains/kotlin/test/directives/LanguageSettingsDirectives.kt index b9236d38a46..e94b4f35764 100644 --- a/compiler/test-infrastructure/tests/org/jetbrains/kotlin/test/directives/LanguageSettingsDirectives.kt +++ b/compiler/test-infrastructure/tests/org/jetbrains/kotlin/test/directives/LanguageSettingsDirectives.kt @@ -75,6 +75,7 @@ object LanguageSettingsDirectives : SimpleDirectivesContainer() { val PARAMETERS_METADATA by directive("Add parameters metadata for 1.8 reflection") val USE_TYPE_TABLE by directive("Use type table in metadata serialization") val NO_NEW_JAVA_ANNOTATION_TARGETS by directive("Do not generate Java annotation targets TYPE_USE/TYPE_PARAMETER for Kotlin annotation classes with Kotlin targets TYPE/TYPE_PARAMETER") + val OLD_INNER_CLASSES_LOGIC by directive("Use old logic for generation of InnerClasses attributes") // --------------------- Utils --------------------- diff --git a/compiler/testData/cli/jvm/extraHelp.out b/compiler/testData/cli/jvm/extraHelp.out index 139d6f1f1a1..1c045054f06 100644 --- a/compiler/testData/cli/jvm/extraHelp.out +++ b/compiler/testData/cli/jvm/extraHelp.out @@ -108,6 +108,7 @@ where advanced options include: * ignore * strict * warn (report a warning) + -Xuse-old-innerclasses-logic Use old logic for generation of InnerClasses attributes -Xprofile= Debug option: Run compiler with async profiler and save snapshots to `outputDir`; `command` is passed to async-profiler on start. `profilerPath` is a path to libasyncProfiler.so; async-profiler.jar should be on the compiler classpath. diff --git a/compiler/testData/codegen/bytecodeText/innerClasses/kt53804.kt b/compiler/testData/codegen/bytecodeText/innerClasses/kt53804.kt new file mode 100644 index 00000000000..417529c893a --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/innerClasses/kt53804.kt @@ -0,0 +1,142 @@ +// OLD_INNER_CLASSES_LOGIC +// TARGET_BACKEND: JVM_IR + +// FILE: classes.kt + +public class A0 { + public class B0 { + public class C0 { + public class D0 + } + } +} + +public class A1 { + public class B1 { + public class C1 { + public class D1 + } + } +} + +public class A2 { + public class B2 { + public class C2 { + public class D2 + } + } +} + +object A3 { + interface B3 { + interface C3 { + interface D3 + } + } +} + +public class A4 { + public class B4 { + public class C4 { + public class D4 + } + } +} + +public class A5 { + public class B5 { + public class C5 { + public class D5 + } + } +} + +public class A6 { + public class B6 { + public class C6 { + public class D6 + } + } +} + +@Target(AnnotationTarget.VALUE_PARAMETER) +@Retention(AnnotationRetention.RUNTIME) +annotation class ClassHolder(val value: kotlin.reflect.KClass<*>) + +public class A7 { + public class B7 { + public class C7 { + public class D7 + } + } +} + +@JvmInline +public value class A8(private val value: Int) { + @JvmInline + public value class B8(private val value: Int) { + @JvmInline + public value class C8(private val value: Int) { + @JvmInline + public value class D8(private val value: Int) + } + } +} + + +inline fun foo() = null + + +// FILE: X.kt +class X { + fun f0(t: List>>) {} + fun f1(): A1.B1.C1? = null + fun f2() { + foo() + } + fun f3(x: Any): Any? = x as? A3.B3.C3 + fun f4(): String { + val x = listOf() + return x.toString() + } + + class Y { + fun f5(): String { + val x: A5.B5.C5? = null + return x.toString() + } + fun f6(): A6.B6.C6? = null + + fun f7(@ClassHolder(A7.B7.C7::class) x: Int) {} + + fun f8() = A8.B8.C8::class.toString() + } +} + + +// @X.class: +// 1 INNERCLASS +// 0 INNERCLASS java.lang.Thread\$State java.lang.Thread State +// 0 INNERCLASS A0\$B0 A0 B0 +// 0 INNERCLASS A0\$B0\$C0 A0\$B0 C0 +// 0 INNERCLASS A1\$B1 A1 B1 +// 0 INNERCLASS A1\$B1\$C1 A1\$B1 C1 +// 0 INNERCLASS A2\$B2 A2 B2 +// 0 INNERCLASS A2\$B2\$C2 A2\$B2 C2 +// 0 INNERCLASS A3\$B3 A3 B3 +// 0 INNERCLASS A3\$B3\$C3 A3\$B3 C3 +// 0 INNERCLASS A4\$B4 A4 B4 +// 0 INNERCLASS A4\$B4\$C4 A4\$B4 C4 +// 1 INNERCLASS X\$Y X Y + +// @X$Y.class: +// 3 INNERCLASS +// 1 INNERCLASS X\$Y X Y +// 0 INNERCLASS A5\$B5 A5 B5 +// 0 INNERCLASS A5\$B5\$C5 A5\$B5 C5 +// 0 INNERCLASS A6\$B6 A6 B6 +// 0 INNERCLASS A6\$B6\$C6 A6\$B6 C6 +// 1 INNERCLASS A7\$B7 A7 B7 +// 1 INNERCLASS A7\$B7\$C7 A7\$B7 C7 +// 0 INNERCLASS A8\$B8 A8 B8 +// 0 INNERCLASS A8\$B8\$C8 A8\$B8 C8 diff --git a/compiler/testData/codegen/bytecodeText/innerClasses/nestedClassInAnnotationArgumentOldMode.kt b/compiler/testData/codegen/bytecodeText/innerClasses/nestedClassInAnnotationArgumentOldMode.kt new file mode 100644 index 00000000000..856b4f88819 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/innerClasses/nestedClassInAnnotationArgumentOldMode.kt @@ -0,0 +1,46 @@ +// OLD_INNER_CLASSES_LOGIC +// TARGET_BACKEND: JVM_IR + +// FILE: annotations.kt + +import kotlin.reflect.* + +annotation class Anno( + val k: KClass<*>, + val e: C.NestedEnum, + val a: C.NestedAnno, +) + +annotation class AnnoWithDefault(val k: KClass<*> = Nested0::class) { + class Nested0 +} + +class C { + class Nested1 + + enum class NestedEnum { E } + + annotation class NestedAnno(val k: KClass<*>) { + class Nested2 + } +} + +// FILE: usage.kt + +interface I { + @Anno( + C.Nested1::class, + C.NestedEnum.E, + C.NestedAnno(C.NestedAnno.Nested2::class), + ) + @AnnoWithDefault + fun foo(): String = "OK" +} + +// @I.class: +// 5 INNERCLASS +// 1 INNERCLASS C\$Nested1 C Nested1 +// 1 INNERCLASS C\$NestedEnum C NestedEnum +// 1 INNERCLASS C\$NestedAnno C NestedAnno +// 1 INNERCLASS C\$NestedAnno\$Nested2 C\$NestedAnno Nested2 +// 1 INNERCLASS I\$DefaultImpls I DefaultImpls \ No newline at end of file diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeTextTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeTextTestGenerated.java index dfb37ee1dbe..10e1a514ab3 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeTextTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeTextTestGenerated.java @@ -4054,11 +4054,23 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/innerClasses/kt27936.kt"); } + @Test + @TestMetadata("kt53804.kt") + public void testKt53804() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/innerClasses/kt53804.kt"); + } + @Test @TestMetadata("nestedClassInAnnotationArgument.kt") public void testNestedClassInAnnotationArgument() throws Exception { runTest("compiler/testData/codegen/bytecodeText/innerClasses/nestedClassInAnnotationArgument.kt"); } + + @Test + @TestMetadata("nestedClassInAnnotationArgumentOldMode.kt") + public void testNestedClassInAnnotationArgumentOldMode() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/innerClasses/nestedClassInAnnotationArgumentOldMode.kt"); + } } @Nested diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/configuration/JvmEnvironmentConfigurator.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/configuration/JvmEnvironmentConfigurator.kt index 639fae91e09..eae4e1cde62 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/configuration/JvmEnvironmentConfigurator.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/configuration/JvmEnvironmentConfigurator.kt @@ -49,6 +49,7 @@ import org.jetbrains.kotlin.test.directives.LanguageSettingsDirectives.NO_UNIFIE import org.jetbrains.kotlin.test.directives.LanguageSettingsDirectives.PARAMETERS_METADATA import org.jetbrains.kotlin.test.directives.LanguageSettingsDirectives.JDK_RELEASE import org.jetbrains.kotlin.test.directives.LanguageSettingsDirectives.NO_NEW_JAVA_ANNOTATION_TARGETS +import org.jetbrains.kotlin.test.directives.LanguageSettingsDirectives.OLD_INNER_CLASSES_LOGIC import org.jetbrains.kotlin.test.directives.LanguageSettingsDirectives.USE_TYPE_TABLE import org.jetbrains.kotlin.test.directives.model.DirectivesContainer import org.jetbrains.kotlin.test.directives.model.RegisteredDirectives @@ -175,6 +176,7 @@ class JvmEnvironmentConfigurator(testServices: TestServices) : EnvironmentConfig register(USE_TYPE_TABLE, JVMConfigurationKeys.USE_TYPE_TABLE) register(ENABLE_DEBUG_MODE, JVMConfigurationKeys.ENABLE_DEBUG_MODE) register(NO_NEW_JAVA_ANNOTATION_TARGETS, JVMConfigurationKeys.NO_NEW_JAVA_ANNOTATION_TARGETS) + register(OLD_INNER_CLASSES_LOGIC, JVMConfigurationKeys.OLD_INNER_CLASSES_LOGIC) } override fun configureCompilerConfiguration(configuration: CompilerConfiguration, module: TestModule) { diff --git a/libraries/stdlib/jvm/build.gradle b/libraries/stdlib/jvm/build.gradle index 66a9af96459..aebc2d29fc8 100644 --- a/libraries/stdlib/jvm/build.gradle +++ b/libraries/stdlib/jvm/build.gradle @@ -118,6 +118,7 @@ compileKotlin { "-Xbuiltins-from-sources", "-XXLanguage:+RangeUntilOperator", "-Xno-new-java-annotation-targets", + "-Xuse-old-innerclasses-logic", ] moduleName = "kotlin-stdlib" }