From 543db380d282f74a59b77627cd1b66a5d129743d Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Tue, 23 Jan 2018 18:55:13 +0100 Subject: [PATCH] Use isJvmInterface in JVM back-end instead of isInterface To support const vals and proper initialization order for companions of annotations (since 1.3+) as well as interfaces #KT-16962 Fixed --- .../org/jetbrains/kotlin/codegen/AsmUtil.java | 2 +- .../codegen/ImplementationBodyCodegen.java | 10 +++-- .../kotlin/codegen/JvmCodegenUtil.java | 8 ++++ .../jetbrains/kotlin/codegen/codegenUtil.kt | 4 +- .../backend/jvm/codegen/ClassCodegen.kt | 2 +- .../backend/jvm/lower/ObjectClassLowering.kt | 2 +- .../box/annotations/constValInAnnotation.kt | 19 ++++++++++ .../interfaceCompanionObjectReference.kt | 37 ++++++++++++++++++- .../ir/IrBlackBoxCodegenTestGenerated.java | 6 +++ .../codegen/BlackBoxCodegenTestGenerated.java | 6 +++ .../LightAnalysisModeTestGenerated.java | 6 +++ .../jetbrains/kotlin/load/java/JvmAbi.java | 7 ---- 12 files changed, 92 insertions(+), 17 deletions(-) create mode 100644 compiler/testData/codegen/box/annotations/constValInAnnotation.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java index 3d65515ed24..f09e9ae8af2 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java @@ -781,7 +781,7 @@ public class AsmUtil { public static boolean isPropertyWithBackingFieldCopyInOuterClass(@NotNull PropertyDescriptor propertyDescriptor) { DeclarationDescriptor propertyContainer = propertyDescriptor.getContainingDeclaration(); return propertyDescriptor.isConst() - && isCompanionObject(propertyContainer) && isInterface(propertyContainer.getContainingDeclaration()) + && isCompanionObject(propertyContainer) && isJvmInterface(propertyContainer.getContainingDeclaration()) && getVisibilityForBackingField(propertyDescriptor, false) == ACC_PUBLIC; } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java index 2168bafc397..ec95dad43ae 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java @@ -52,7 +52,8 @@ import org.jetbrains.kotlin.resolve.DelegationResolver; import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils; import org.jetbrains.kotlin.resolve.DescriptorUtils; import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt; -import org.jetbrains.kotlin.resolve.calls.model.*; +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; +import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall; import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt; import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin; import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt; @@ -64,7 +65,10 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver; import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver; import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue; import org.jetbrains.kotlin.types.KotlinType; -import org.jetbrains.org.objectweb.asm.*; +import org.jetbrains.org.objectweb.asm.FieldVisitor; +import org.jetbrains.org.objectweb.asm.Label; +import org.jetbrains.org.objectweb.asm.MethodVisitor; +import org.jetbrains.org.objectweb.asm.Type; import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter; import org.jetbrains.org.objectweb.asm.commons.Method; @@ -974,7 +978,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { } private void generatePrimaryConstructor(DelegationFieldsInfo delegationFieldsInfo) { - if (isInterface(descriptor) || isAnnotationClass(descriptor)) return; + if (isJvmInterface(descriptor)) return; ClassConstructorDescriptor constructorDescriptor = descriptor.getUnsubstitutedPrimaryConstructor(); if (constructorDescriptor == null) return; diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmCodegenUtil.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmCodegenUtil.java index 7dc69551c8f..aad91e722b5 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmCodegenUtil.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmCodegenUtil.java @@ -31,6 +31,7 @@ import org.jetbrains.kotlin.codegen.state.GenerationState; import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper; import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor; +import org.jetbrains.kotlin.load.java.JvmAbi; import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor; import org.jetbrains.kotlin.load.java.descriptors.JavaPropertyDescriptor; import org.jetbrains.kotlin.load.kotlin.*; @@ -57,6 +58,7 @@ import static org.jetbrains.kotlin.descriptors.ClassKind.INTERFACE; import static org.jetbrains.kotlin.descriptors.Modality.ABSTRACT; import static org.jetbrains.kotlin.descriptors.Modality.FINAL; import static org.jetbrains.kotlin.resolve.BindingContext.DELEGATED_PROPERTY_CALL; +import static org.jetbrains.kotlin.resolve.DescriptorUtils.isCompanionObject; import static org.jetbrains.kotlin.resolve.jvm.annotations.AnnotationUtilKt.hasJvmFieldAnnotation; public class JvmCodegenUtil { @@ -330,4 +332,10 @@ public class JvmCodegenUtil { return receiver; } + + public static boolean isCompanionObjectInInterfaceNotIntrinsic(@NotNull DeclarationDescriptor companionObject) { + return isCompanionObject(companionObject) && + isJvmInterface(companionObject.getContainingDeclaration()) && + !JvmAbi.isMappedIntrinsicCompanionObject((ClassDescriptor) companionObject); + } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt index 8a542f4c99d..48448394eb0 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt @@ -429,7 +429,7 @@ fun ExpressionCodegen.generateCallSingleArgument(call: ResolvedCall.parentContextsWithSelf get() = generateSequence(this) { it.parentContext } @@ -438,4 +438,4 @@ val CodegenContext<*>.parentContexts get() = parentContext?.parentContextsWithSelf ?: emptySequence() val CodegenContext<*>.contextStackText - get() = parentContextsWithSelf.joinToString(separator = "\n") { it.toString() } \ No newline at end of file + get() = parentContextsWithSelf.joinToString(separator = "\n") { it.toString() } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt index 85cf42996d3..28d102ccc11 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt @@ -188,7 +188,7 @@ class ClassCodegen private constructor( fun ClassDescriptor.calculateClassFlags(): Int { var flags = 0 - flags = flags or if (DescriptorUtils.isInterface(this) || DescriptorUtils.isAnnotationClass(this)) Opcodes.ACC_INTERFACE else Opcodes.ACC_SUPER + flags = flags or if (JvmCodegenUtil.isJvmInterface(this)) Opcodes.ACC_INTERFACE else Opcodes.ACC_SUPER flags = flags or calcModalityFlag() flags = flags or AsmUtil.getVisibilityAccessFlagForClass(this) flags = flags or if (kind == ClassKind.ENUM_CLASS) Opcodes.ACC_ENUM else 0 diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ObjectClassLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ObjectClassLowering.kt index f4f76e0a53c..1cac5da3eed 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ObjectClassLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ObjectClassLowering.kt @@ -32,7 +32,7 @@ import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBodyImpl import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl -import org.jetbrains.kotlin.load.java.JvmAbi.isCompanionObjectInInterfaceNotIntrinsic +import org.jetbrains.kotlin.codegen.JvmCodegenUtil.isCompanionObjectInInterfaceNotIntrinsic class ObjectClassLowering(val context: JvmBackendContext) : IrElementTransformerVoidWithContext(), FileLoweringPass { diff --git a/compiler/testData/codegen/box/annotations/constValInAnnotation.kt b/compiler/testData/codegen/box/annotations/constValInAnnotation.kt new file mode 100644 index 00000000000..af1eb239a42 --- /dev/null +++ b/compiler/testData/codegen/box/annotations/constValInAnnotation.kt @@ -0,0 +1,19 @@ +// !LANGUAGE: +NestedClassesInAnnotations +// WITH_RUNTIME +// TARGET_BACKEND: JVM +// FILE: Foo.java + +@Anno(Anno.CONST) +public class Foo {} + +// FILE: Anno.kt + +annotation class Anno(val value: Int) { + companion object { + const val CONST = 42 + } +} + +fun box(): String = + if ((Foo::class.java.annotations.single() as Anno).value == 42) "OK" else "Fail" + diff --git a/compiler/testData/codegen/box/objects/interfaceCompanionObjectReference.kt b/compiler/testData/codegen/box/objects/interfaceCompanionObjectReference.kt index 6624b0a2bc9..34e65303514 100644 --- a/compiler/testData/codegen/box/objects/interfaceCompanionObjectReference.kt +++ b/compiler/testData/codegen/box/objects/interfaceCompanionObjectReference.kt @@ -1,10 +1,11 @@ +// !LANGUAGE: +NestedClassesInAnnotations // WITH_RUNTIME import kotlin.test.* interface Test { companion object { - val x = "OK" + val x = "O" val y1 = Test.x @@ -34,4 +35,36 @@ interface Test { } } -fun box() = Test.x \ No newline at end of file +annotation class Anno { + companion object { + val x = "K" + + val y1 = Anno.x + + val y2 = 42.let { x } + + val y3: String + init { + fun localFun() = x + y3 = localFun() + } + + fun method() = x + val y4 = method() + + val anonObject = object { + override fun toString() = x + } + val y5 = anonObject.toString() + + init { + assertEquals(x, y1) + assertEquals(x, y2) + assertEquals(x, y3) + assertEquals(x, y4) + assertEquals(x, y5) + } + } +} + +fun box() = Test.x + Anno.x diff --git a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index c531a37f670..6310f4f2c8b 100644 --- a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -69,6 +69,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes doTest(fileName); } + @TestMetadata("constValInAnnotation.kt") + public void testConstValInAnnotation() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/annotations/constValInAnnotation.kt"); + doTest(fileName); + } + @TestMetadata("defaultParameterValues.kt") public void testDefaultParameterValues() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/annotations/defaultParameterValues.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 712e47652ef..a7736ffb75a 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -69,6 +69,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("constValInAnnotation.kt") + public void testConstValInAnnotation() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/annotations/constValInAnnotation.kt"); + doTest(fileName); + } + @TestMetadata("defaultParameterValues.kt") public void testDefaultParameterValues() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/annotations/defaultParameterValues.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 9af299bfc53..da9c16b9fe7 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -81,6 +81,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes doTest(fileName); } + @TestMetadata("constValInAnnotation.kt") + public void testConstValInAnnotation() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/annotations/constValInAnnotation.kt"); + doTest(fileName); + } + @TestMetadata("defaultParameterValues.kt") public void testDefaultParameterValues() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/annotations/defaultParameterValues.kt"); diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/JvmAbi.java b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/JvmAbi.java index 0d2b6746927..7e930a8fd85 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/JvmAbi.java +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/JvmAbi.java @@ -29,7 +29,6 @@ import org.jetbrains.kotlin.util.capitalizeDecapitalize.CapitalizeDecapitalizeKt import static org.jetbrains.kotlin.resolve.DescriptorUtils.isClassOrEnumClass; import static org.jetbrains.kotlin.resolve.DescriptorUtils.isCompanionObject; -import static org.jetbrains.kotlin.resolve.DescriptorUtils.isInterface; public final class JvmAbi { public static final String DEFAULT_IMPLS_CLASS_NAME = "DefaultImpls"; @@ -118,10 +117,4 @@ public final class JvmAbi { public static boolean isMappedIntrinsicCompanionObject(@NotNull ClassDescriptor companionObject) { return CompanionObjectMapping.INSTANCE.isMappedIntrinsicCompanionObject(companionObject); } - - public static boolean isCompanionObjectInInterfaceNotIntrinsic(@NotNull DeclarationDescriptor companionObject) { - return isCompanionObject(companionObject) && - isInterface(companionObject.getContainingDeclaration()) && - !isMappedIntrinsicCompanionObject((ClassDescriptor) companionObject); - } }