diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmGeneratorExtensions.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmGeneratorExtensions.kt index ad6c5fcbc2e..13608a5a0dc 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmGeneratorExtensions.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmGeneratorExtensions.kt @@ -10,12 +10,16 @@ import org.jetbrains.kotlin.backend.common.ir.createParameterDeclarations import org.jetbrains.kotlin.codegen.SamType import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.FilteredAnnotations +import org.jetbrains.kotlin.incremental.components.NoLookupLocation +import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI import org.jetbrains.kotlin.ir.builders.declarations.addConstructor import org.jetbrains.kotlin.ir.builders.declarations.buildClass import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns +import org.jetbrains.kotlin.ir.expressions.IrDelegatingConstructorCall +import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl import org.jetbrains.kotlin.ir.symbols.impl.DescriptorlessExternalPackageFragmentSymbol import org.jetbrains.kotlin.ir.util.constructors import org.jetbrains.kotlin.load.java.JvmAnnotationNames @@ -27,11 +31,19 @@ import org.jetbrains.kotlin.load.java.typeEnhancement.hasEnhancedNullability import org.jetbrains.kotlin.load.kotlin.JvmPackagePartSource import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.psi.KtPureClassOrObject +import org.jetbrains.kotlin.psi.psiUtil.pureEndOffset +import org.jetbrains.kotlin.psi.psiUtil.pureStartOffset +import org.jetbrains.kotlin.psi2ir.generators.GeneratorContext import org.jetbrains.kotlin.psi2ir.generators.GeneratorExtensions import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.annotations.hasJvmStaticAnnotation +import org.jetbrains.kotlin.resolve.descriptorUtil.module +import org.jetbrains.kotlin.resolve.descriptorUtil.resolveTopLevelClass +import org.jetbrains.kotlin.resolve.jvm.JAVA_LANG_RECORD_FQ_NAME import org.jetbrains.kotlin.resolve.jvm.JvmClassName import org.jetbrains.kotlin.resolve.jvm.annotations.hasJvmFieldAnnotation +import org.jetbrains.kotlin.resolve.jvm.annotations.isJvmRecord import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource import org.jetbrains.kotlin.types.KotlinType @@ -127,6 +139,28 @@ class JvmGeneratorExtensions(private val generateFacades: Boolean = true) : Gene } } + override fun createCustomSuperConstructorCall( + ktPureClassOrObject: KtPureClassOrObject, + descriptor: ClassDescriptor, + context: GeneratorContext + ): IrDelegatingConstructorCall? { + if (!descriptor.isJvmRecord()) return null + + val recordClass = + // We assume j.l.Record is in the classpath because otherwise it should be a compile time error + descriptor.module.resolveTopLevelClass(JAVA_LANG_RECORD_FQ_NAME, NoLookupLocation.FROM_BACKEND) + ?: error("Class not found: $JAVA_LANG_RECORD_FQ_NAME") + + val recordConstructor = recordClass.constructors.single() + // OptIn is needed for the same as for Any constructor at BodyGenerator::generateAnySuperConstructorCall + @OptIn(ObsoleteDescriptorBasedAPI::class) + return IrDelegatingConstructorCallImpl.fromSymbolDescriptor( + ktPureClassOrObject.pureStartOffset, ktPureClassOrObject.pureEndOffset, + context.irBuiltIns.unitType, + context.symbolTable.referenceConstructor(recordConstructor) + ) + } + private val flexibleNullabilityAnnotationClass = createSpecialAnnotationClass(FLEXIBLE_NULLABILITY_ANNOTATION_FQ_NAME, kotlinIrInternalPackage) diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/BodyGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/BodyGenerator.kt index 3305347b82e..2428ac4c49f 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/BodyGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/BodyGenerator.kt @@ -217,6 +217,11 @@ class BodyGenerator( private fun generateSuperConstructorCall(body: IrBlockBody, ktClassOrObject: KtPureClassOrObject) { val classDescriptor = ktClassOrObject.findClassDescriptor(context.bindingContext) + context.extensions.createCustomSuperConstructorCall(ktClassOrObject, classDescriptor, context)?.let { + body.statements.add(it) + return + } + when (classDescriptor.kind) { // enums can't be synthetic ClassKind.ENUM_CLASS -> generateEnumSuperConstructorCall(body, ktClassOrObject as KtClassOrObject, classDescriptor) diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/GeneratorExtensions.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/GeneratorExtensions.kt index 56e9c8008ff..7e0b83e2c42 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/GeneratorExtensions.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/GeneratorExtensions.kt @@ -6,10 +6,12 @@ package org.jetbrains.kotlin.psi2ir.generators import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.DescriptorVisibility import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor -import org.jetbrains.kotlin.descriptors.DescriptorVisibility +import org.jetbrains.kotlin.ir.expressions.IrDelegatingConstructorCall import org.jetbrains.kotlin.ir.util.StubGeneratorExtensions +import org.jetbrains.kotlin.psi.KtPureClassOrObject import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.types.KotlinType @@ -29,4 +31,10 @@ open class GeneratorExtensions : StubGeneratorExtensions() { open fun computeFieldVisibility(descriptor: PropertyDescriptor): DescriptorVisibility? = null open fun getParentClassStaticScope(descriptor: ClassDescriptor): MemberScope? = null + + open fun createCustomSuperConstructorCall( + ktPureClassOrObject: KtPureClassOrObject, + descriptor: ClassDescriptor, + context: GeneratorContext, + ): IrDelegatingConstructorCall? = null } diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/AbstractJdk15IrBlackBoxCodegenTest.kt b/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/AbstractJdk15IrBlackBoxCodegenTest.kt new file mode 100644 index 00000000000..199427f71c6 --- /dev/null +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/AbstractJdk15IrBlackBoxCodegenTest.kt @@ -0,0 +1,13 @@ +/* + * 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 + +import org.jetbrains.kotlin.test.TargetBackend + +abstract class AbstractJdk15IrBlackBoxCodegenTest : AbstractJdk15BlackBoxCodegenTest() { + override val backend: TargetBackend + get() = TargetBackend.JVM_IR +} diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/Jdk15IrBlackBoxCodegenTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/Jdk15IrBlackBoxCodegenTestGenerated.java new file mode 100644 index 00000000000..a1ac4871c41 --- /dev/null +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/Jdk15IrBlackBoxCodegenTestGenerated.java @@ -0,0 +1,68 @@ +/* + * 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; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.JUnit3RunnerWithInners; +import org.jetbrains.kotlin.test.KotlinTestUtils; +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/java15/box") +@TestDataPath("$PROJECT_ROOT") +@RunWith(JUnit3RunnerWithInners.class) +public class Jdk15IrBlackBoxCodegenTestGenerated extends AbstractJdk15IrBlackBoxCodegenTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInBox() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/java15/box"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @TestMetadata("compiler/testData/codegen/java15/box/records") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Records extends AbstractJdk15IrBlackBoxCodegenTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInRecords() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/java15/box/records"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @TestMetadata("bytecodeShapeForJava.kt") + public void testBytecodeShapeForJava() throws Exception { + runTest("compiler/testData/codegen/java15/box/records/bytecodeShapeForJava.kt"); + } + + @TestMetadata("dataJvmRecord.kt") + public void testDataJvmRecord() throws Exception { + runTest("compiler/testData/codegen/java15/box/records/dataJvmRecord.kt"); + } + + @TestMetadata("recordDifferentPropertyOverride.kt") + public void testRecordDifferentPropertyOverride() throws Exception { + runTest("compiler/testData/codegen/java15/box/records/recordDifferentPropertyOverride.kt"); + } + + @TestMetadata("recordDifferentSyntheticProperty.kt") + public void testRecordDifferentSyntheticProperty() throws Exception { + runTest("compiler/testData/codegen/java15/box/records/recordDifferentSyntheticProperty.kt"); + } + + @TestMetadata("recordPropertyAccess.kt") + public void testRecordPropertyAccess() throws Exception { + runTest("compiler/testData/codegen/java15/box/records/recordPropertyAccess.kt"); + } + } +} diff --git a/compiler/tests/org/jetbrains/kotlin/generators/tests/GenerateCompilerTests.kt b/compiler/tests/org/jetbrains/kotlin/generators/tests/GenerateCompilerTests.kt index f06e2aba8f4..9d4dd0e0e52 100644 --- a/compiler/tests/org/jetbrains/kotlin/generators/tests/GenerateCompilerTests.kt +++ b/compiler/tests/org/jetbrains/kotlin/generators/tests/GenerateCompilerTests.kt @@ -215,6 +215,10 @@ fun main(args: Array) { model("codegen/java15/box") } + testClass { + model("codegen/java15/box") + } + testClass { model("codegen/java9/box") }