Support @JvmRecord for JVM_IR

^KT-43677 In Progress
This commit is contained in:
Denis.Zharkov
2020-12-01 19:16:27 +03:00
parent f64980a597
commit a4bf36aee7
6 changed files with 133 additions and 1 deletions
@@ -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)
@@ -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)
@@ -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
}
@@ -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
}
@@ -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");
}
}
}
@@ -215,6 +215,10 @@ fun main(args: Array<String>) {
model("codegen/java15/box")
}
testClass<AbstractJdk15IrBlackBoxCodegenTest> {
model("codegen/java15/box")
}
testClass<AbstractJdk9BlackBoxCodegenTest> {
model("codegen/java9/box")
}