Kapt: never generate enums as final

Behavior differs between JVM and JVM_IR backends here because in JVM,
the class descriptor comes from the frontend, and its modality for enum
is never final. For JVM IR, the class descriptor is based on IrClass,
whose modality is sometimes final for enum, presumably because it's
easier for backends (see `ClassGenerator.getEffectiveModality`).

 #KT-49682
This commit is contained in:
Alexander Udalov
2021-12-16 00:19:07 +01:00
parent fc2c0eea27
commit b3820564b0
8 changed files with 82 additions and 20 deletions
@@ -50,13 +50,16 @@ import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.ArrayFqNames import org.jetbrains.kotlin.resolve.ArrayFqNames
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DelegatingBindingTrace import org.jetbrains.kotlin.resolve.DelegatingBindingTrace
import org.jetbrains.kotlin.resolve.calls.util.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.util.getType
import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument
import org.jetbrains.kotlin.resolve.calls.util.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.util.getType
import org.jetbrains.kotlin.resolve.constants.* import org.jetbrains.kotlin.resolve.constants.*
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
import org.jetbrains.kotlin.resolve.descriptorUtil.* import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
import org.jetbrains.kotlin.resolve.descriptorUtil.isCompanionObject
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
import org.jetbrains.kotlin.resolve.source.getPsi import org.jetbrains.kotlin.resolve.source.getPsi
import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.types.ErrorUtils
@@ -646,15 +649,22 @@ class ClassFileToSourceStubConverter(val kaptContext: KaptContextForStubGenerati
return doesInnerClassNameConflictWithOuter(clazz, containingClassForOuterClass) return doesInnerClassNameConflictWithOuter(clazz, containingClassForOuterClass)
} }
private fun getClassAccessFlags(clazz: ClassNode, descriptor: DeclarationDescriptor, isInner: Boolean, isNested: Boolean) = when { private fun getClassAccessFlags(clazz: ClassNode, descriptor: DeclarationDescriptor, isInner: Boolean, isNested: Boolean): Int {
(descriptor.containingDeclaration as? ClassDescriptor)?.kind == ClassKind.INTERFACE -> { if ((descriptor.containingDeclaration as? ClassDescriptor)?.kind == ClassKind.INTERFACE) {
// Classes inside interfaces should always be public and static. // Classes inside interfaces should always be public and static.
// See com.sun.tools.javac.comp.Enter.visitClassDef for more information. // See com.sun.tools.javac.comp.Enter.visitClassDef for more information.
(clazz.access or Opcodes.ACC_PUBLIC or Opcodes.ACC_STATIC) and return (clazz.access or Opcodes.ACC_PUBLIC or Opcodes.ACC_STATIC) and
Opcodes.ACC_PRIVATE.inv() and Opcodes.ACC_PROTECTED.inv() // Remove private and protected modifiers Opcodes.ACC_PRIVATE.inv() and Opcodes.ACC_PROTECTED.inv() // Remove private and protected modifiers
} }
!isInner && isNested -> clazz.access or Opcodes.ACC_STATIC var access = clazz.access
else -> clazz.access if ((descriptor as? ClassDescriptor)?.kind == ClassKind.ENUM_CLASS) {
// Enums are final in the bytecode, but "final enum" is not allowed in Java.
access = access and Opcodes.ACC_FINAL.inv()
}
if (!isInner && isNested) {
access = access or Opcodes.ACC_STATIC
}
return access
} }
private fun getClassName(clazz: ClassNode, descriptor: DeclarationDescriptor, isDefaultImpls: Boolean, packageFqName: String): String { private fun getClassName(clazz: ClassNode, descriptor: DeclarationDescriptor, isDefaultImpls: Boolean, packageFqName: String): String {
@@ -1,5 +1,3 @@
// IGNORE_BACKEND: JVM_IR
enum class E { enum class E {
X { X {
override fun a() {} override fun a() {}
@@ -1,5 +1,3 @@
// IGNORE_BACKEND: JVM_IR
enum class Enum1 { enum class Enum1 {
BLACK, WHITE BLACK, WHITE
} }
@@ -1,5 +1,3 @@
// IGNORE_BACKEND: JVM_IR
interface Context interface Context
enum class Result { enum class Result {
@@ -1,5 +1,3 @@
// IGNORE_BACKEND: JVM_IR
enum class Color { enum class Color {
BLACK, `WHI-TE` BLACK, `WHI-TE`
} }
@@ -7,5 +5,5 @@ enum class Color {
@Anno(Color.`WHI-TE`) @Anno(Color.`WHI-TE`)
annotation class Anno(val color: Color) annotation class Anno(val color: Color)
// EXPECTED_ERROR(kotlin:7:1) an enum annotation value must be an enum constant // EXPECTED_ERROR(kotlin:5:1) an enum annotation value must be an enum constant
// EXPECTED_ERROR(other:-1:-1) 'WHI-TE' is an invalid Java enum value name // EXPECTED_ERROR(other:-1:-1) 'WHI-TE' is an invalid Java enum value name
@@ -1,5 +1,3 @@
// IGNORE_BACKEND: JVM_IR
class `:)` { class `:)` {
lateinit val f: String lateinit val f: String
} }
@@ -0,0 +1,63 @@
import java.lang.System;
@kotlin.Metadata()
@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
public abstract @interface Anno {
public abstract StrangeEnum size();
public abstract java.lang.String name();
}
////////////////////
import java.lang.System;
@kotlin.Metadata()
public enum StrangeEnum {
/*public static final*/ InvalidFieldName /* = new StrangeEnum() */;
@org.jetbrains.annotations.NotNull()
private final java.lang.String size = null;
StrangeEnum(java.lang.String size) {
}
@org.jetbrains.annotations.NotNull()
public final java.lang.String getSize() {
return null;
}
}
////////////////////
import java.lang.System;
@kotlin.Metadata()
public final class Test {
public final java.lang.String simpleName = null;
public Test() {
super();
}
@org.jetbrains.annotations.NotNull()
public final java.lang.String getSimpleName() {
return null;
}
public final void simpleFun() {
}
@Anno(size = StrangeEnum.InvalidFieldName, name = "Woofwoof")
public final void simpleFun2(@org.jetbrains.annotations.NotNull()
java.lang.String a, @org.jetbrains.annotations.NotNull()
java.lang.String b) {
}
public final void strangeFun4(@org.jetbrains.annotations.NotNull()
java.lang.String a, @org.jetbrains.annotations.NotNull()
java.lang.String p1_949560896) {
}
}
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// STRIP_METADATA // STRIP_METADATA
interface Context interface Context