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
This commit is contained in:
Alexander Udalov
2018-01-23 18:55:13 +01:00
parent a46a2b9b1c
commit 543db380d2
12 changed files with 92 additions and 17 deletions
@@ -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;
}
@@ -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;
@@ -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);
}
}
@@ -429,7 +429,7 @@ fun ExpressionCodegen.generateCallSingleArgument(call: ResolvedCall<out Callable
fun ClassDescriptor.isPossiblyUninitializedSingleton() =
DescriptorUtils.isEnumEntry(this) ||
DescriptorUtils.isCompanionObject(this) && DescriptorUtils.isInterface(this.containingDeclaration)
DescriptorUtils.isCompanionObject(this) && JvmCodegenUtil.isJvmInterface(this.containingDeclaration)
val CodegenContext<*>.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() }
get() = parentContextsWithSelf.joinToString(separator = "\n") { it.toString() }
@@ -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
@@ -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 {
@@ -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"
@@ -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
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
@@ -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");
@@ -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");
@@ -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");
@@ -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);
}
}