From 6e410cb182764992957bb9a1e2a1005f52658d5b Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Tue, 17 Oct 2017 16:34:17 +0200 Subject: [PATCH] Make TypeConstructor.isFinal return false for enums The reason is that before dc02b2e3ab and 8a0dcca957, TypeConstructor.isFinal for some class descriptors (DeserializedClassDescriptor, LazyJavaClassDescriptor, MutableClassDescriptor) were implemented as `isFinalClass` (which is `modality == FINAL && kind != ENUM_CLASS`), and all others as `modality == FINAL` or simply true/false. This led to differences in behavior depending on the exact instance of the class descriptor. Now that TypeConstructor.isFinal is always `modality == FINAL`, some tests (PseudoValueTestGenerated) fail because the finality of some type constructors changed and these tests render final vs non-final type constructors differently. In this commit, TypeConstructor.isFinal is now made to behave safer, i.e. considering enum class type constructor to be non-final (as was the case earlier for some ClassDescriptor instances). Some diagnostics might disappear (e.g. FINAL_UPPER_BOUND) but it doesn't look like a big deal --- .../basic/ExhaustiveInitialization.values | 52 ++++++------- .../EnumEntryRefersCompanion.values | 4 +- .../ObjectEnumQualifiers.values | 10 +-- .../tests/enum/compareTwoDifferentEnums.kt | 16 ++++ .../tests/enum/compareTwoDifferentEnums.txt | 73 +++++++++++++++++++ .../cannotHaveManyClassUpperBounds.kt | 2 +- .../checkers/DiagnosticsTestGenerated.java | 6 ++ .../DiagnosticsUsingJavacTestGenerated.java | 6 ++ .../types/AbstractClassTypeConstructor.java | 2 +- 9 files changed, 136 insertions(+), 35 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/enum/compareTwoDifferentEnums.kt create mode 100644 compiler/testData/diagnostics/tests/enum/compareTwoDifferentEnums.txt diff --git a/compiler/testData/cfg-variables/basic/ExhaustiveInitialization.values b/compiler/testData/cfg-variables/basic/ExhaustiveInitialization.values index 41056bfa8e2..65873fb72a4 100644 --- a/compiler/testData/cfg-variables/basic/ExhaustiveInitialization.values +++ b/compiler/testData/cfg-variables/basic/ExhaustiveInitialization.values @@ -3,10 +3,10 @@ enum class Direction { NORTH, SOUTH, WEST, EAST } --------------------- - : Direction NEW: magic[FAKE_INITIALIZER](NORTH,) -> - : Direction NEW: magic[FAKE_INITIALIZER](SOUTH,) -> - : Direction NEW: magic[FAKE_INITIALIZER](WEST,) -> - : Direction NEW: magic[FAKE_INITIALIZER](EAST) -> + : {<: Direction} NEW: magic[FAKE_INITIALIZER](NORTH,) -> + : {<: Direction} NEW: magic[FAKE_INITIALIZER](SOUTH,) -> + : {<: Direction} NEW: magic[FAKE_INITIALIZER](WEST,) -> + : {<: Direction} NEW: magic[FAKE_INITIALIZER](EAST) -> ===================== == foo == fun foo(dir: Direction): Int { @@ -20,31 +20,31 @@ fun foo(dir: Direction): Int { return res } --------------------- - : Direction NEW: magic[FAKE_INITIALIZER](dir: Direction) -> - : * NEW: magic[EXHAUSTIVE_WHEN_ELSE](when (dir) { Direction.NORTH -> res = 1 Direction.SOUTH -> res = 2 Direction.WEST -> res = 3 Direction.EAST -> res = 4 }) -> -dir : * NEW: r(dir) -> -NORTH : * NEW: r(NORTH) -> -Direction.NORTH : * COPY -Direction.NORTH : * NEW: magic[EQUALS_IN_WHEN_CONDITION](Direction.NORTH|, ) -> -1 : Int NEW: r(1) -> + : {<: Direction} NEW: magic[FAKE_INITIALIZER](dir: Direction) -> + : * NEW: magic[EXHAUSTIVE_WHEN_ELSE](when (dir) { Direction.NORTH -> res = 1 Direction.SOUTH -> res = 2 Direction.WEST -> res = 3 Direction.EAST -> res = 4 }) -> +dir : * NEW: r(dir) -> +NORTH : * NEW: r(NORTH) -> +Direction.NORTH : * COPY +Direction.NORTH : * NEW: magic[EQUALS_IN_WHEN_CONDITION](Direction.NORTH|, ) -> +1 : Int NEW: r(1) -> res = 1 !: * -SOUTH : * NEW: r(SOUTH) -> -Direction.SOUTH : * COPY -Direction.SOUTH : * NEW: magic[EQUALS_IN_WHEN_CONDITION](Direction.SOUTH|, ) -> -2 : Int NEW: r(2) -> +SOUTH : * NEW: r(SOUTH) -> +Direction.SOUTH : * COPY +Direction.SOUTH : * NEW: magic[EQUALS_IN_WHEN_CONDITION](Direction.SOUTH|, ) -> +2 : Int NEW: r(2) -> res = 2 !: * -WEST : * NEW: r(WEST) -> -Direction.WEST : * COPY -Direction.WEST : * NEW: magic[EQUALS_IN_WHEN_CONDITION](Direction.WEST|, ) -> -3 : Int NEW: r(3) -> +WEST : * NEW: r(WEST) -> +Direction.WEST : * COPY +Direction.WEST : * NEW: magic[EQUALS_IN_WHEN_CONDITION](Direction.WEST|, ) -> +3 : Int NEW: r(3) -> res = 3 !: * -EAST : * NEW: r(EAST) -> -Direction.EAST : * COPY -Direction.EAST : * NEW: magic[EQUALS_IN_WHEN_CONDITION](Direction.EAST|, ) -> -4 : Int NEW: r(4) -> +EAST : * NEW: r(EAST) -> +Direction.EAST : * COPY +Direction.EAST : * NEW: magic[EQUALS_IN_WHEN_CONDITION](Direction.EAST|, ) -> +4 : Int NEW: r(4) -> res = 4 !: * -when (dir) { Direction.NORTH -> res = 1 Direction.SOUTH -> res = 2 Direction.WEST -> res = 3 Direction.EAST -> res = 4 } : * NEW: merge(when (dir) { Direction.NORTH -> res = 1 Direction.SOUTH -> res = 2 Direction.WEST -> res = 3 Direction.EAST -> res = 4 }|!, !, !, !) -> -res : Int NEW: r(res) -> +when (dir) { Direction.NORTH -> res = 1 Direction.SOUTH -> res = 2 Direction.WEST -> res = 3 Direction.EAST -> res = 4 } : * NEW: merge(when (dir) { Direction.NORTH -> res = 1 Direction.SOUTH -> res = 2 Direction.WEST -> res = 3 Direction.EAST -> res = 4 }|!, !, !, !) -> +res : Int NEW: r(res) -> return res !: * -{ val res: Int when (dir) { Direction.NORTH -> res = 1 Direction.SOUTH -> res = 2 Direction.WEST -> res = 3 Direction.EAST -> res = 4 } return res } !: * COPY +{ val res: Int when (dir) { Direction.NORTH -> res = 1 Direction.SOUTH -> res = 2 Direction.WEST -> res = 3 Direction.EAST -> res = 4 } return res } !: * COPY ===================== diff --git a/compiler/testData/cfg/declarations/classesAndObjects/EnumEntryRefersCompanion.values b/compiler/testData/cfg/declarations/classesAndObjects/EnumEntryRefersCompanion.values index 2c0f6a884c9..d4af372640f 100644 --- a/compiler/testData/cfg/declarations/classesAndObjects/EnumEntryRefersCompanion.values +++ b/compiler/testData/cfg/declarations/classesAndObjects/EnumEntryRefersCompanion.values @@ -10,8 +10,8 @@ enum class EE(val x: Int) { --------------------- : Int NEW: magic[FAKE_INITIALIZER](val x: Int) -> : EE.Companion NEW: magic[FAKE_INITIALIZER](companion object { fun foo() = 42 }) -> - : EE NEW: magic[FAKE_INITIALIZER](INSTANCE(Companion.foo()),) -> - : EE NEW: magic[FAKE_INITIALIZER](ANOTHER(foo());) -> + : {<: EE} NEW: magic[FAKE_INITIALIZER](INSTANCE(Companion.foo()),) -> + : {<: EE} NEW: magic[FAKE_INITIALIZER](ANOTHER(foo());) -> : EE.Companion NEW: magic[IMPLICIT_RECEIVER](foo()) -> Companion : EE.Companion NEW: r(Companion) -> foo() : Int NEW: call(foo(), foo|) -> diff --git a/compiler/testData/cfg/declarations/classesAndObjects/ObjectEnumQualifiers.values b/compiler/testData/cfg/declarations/classesAndObjects/ObjectEnumQualifiers.values index 5add0958141..b241676bda5 100644 --- a/compiler/testData/cfg/declarations/classesAndObjects/ObjectEnumQualifiers.values +++ b/compiler/testData/cfg/declarations/classesAndObjects/ObjectEnumQualifiers.values @@ -10,10 +10,10 @@ enum class E(val x: Int) { E1(0) } --------------------- - : Int NEW: magic[FAKE_INITIALIZER](val x: Int) -> - : E NEW: magic[FAKE_INITIALIZER](E1(0)) -> -0 : Int NEW: r(0) -> -(0) : * NEW: call((0), |) -> + : Int NEW: magic[FAKE_INITIALIZER](val x: Int) -> + : {<: E} NEW: magic[FAKE_INITIALIZER](E1(0)) -> +0 : Int NEW: r(0) -> +(0) : * NEW: call((0), |) -> ===================== == C == class C { @@ -26,7 +26,7 @@ class C { == foo == fun foo() = E1.x + O.y + C.z --------------------- -E1 : E NEW: r(E1) -> +E1 : {<: E} NEW: r(E1) -> x : Int NEW: r(x|) -> E1.x : Int COPY O : O NEW: r(O) -> diff --git a/compiler/testData/diagnostics/tests/enum/compareTwoDifferentEnums.kt b/compiler/testData/diagnostics/tests/enum/compareTwoDifferentEnums.kt new file mode 100644 index 00000000000..b07eaeb661f --- /dev/null +++ b/compiler/testData/diagnostics/tests/enum/compareTwoDifferentEnums.kt @@ -0,0 +1,16 @@ +// FILE: JavaEnumA.java + +public enum JavaEnumA {} + +// FILE: JavaEnumB.java + +public enum JavaEnumB {} + +// FILE: test.kt + +enum class KotlinEnumA +enum class KotlinEnumB + +fun jj(a: JavaEnumA, b: JavaEnumB) = a == b +fun jk(a: JavaEnumA, b: KotlinEnumB) = a == b +fun kk(a: KotlinEnumA, b: KotlinEnumB) = a == b diff --git a/compiler/testData/diagnostics/tests/enum/compareTwoDifferentEnums.txt b/compiler/testData/diagnostics/tests/enum/compareTwoDifferentEnums.txt new file mode 100644 index 00000000000..d653e74ba6f --- /dev/null +++ b/compiler/testData/diagnostics/tests/enum/compareTwoDifferentEnums.txt @@ -0,0 +1,73 @@ +package + +public fun jj(/*0*/ a: JavaEnumA, /*1*/ b: JavaEnumB): kotlin.Boolean +public fun jk(/*0*/ a: JavaEnumA, /*1*/ b: KotlinEnumB): kotlin.Boolean +public fun kk(/*0*/ a: KotlinEnumA, /*1*/ b: KotlinEnumB): kotlin.Boolean + +public final enum class JavaEnumA : kotlin.Enum { + public constructor JavaEnumA() + public final override /*1*/ /*fake_override*/ val name: kotlin.String + public final override /*1*/ /*fake_override*/ val ordinal: kotlin.Int + protected final override /*1*/ /*fake_override*/ fun clone(): kotlin.Any + public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: JavaEnumA!): kotlin.Int + public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + protected/*protected and package*/ final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun finalize(): kotlin.Unit + public final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun getDeclaringClass(): java.lang.Class! + public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + // Static members + public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): JavaEnumA + public final /*synthesized*/ fun values(): kotlin.Array +} + +public final enum class JavaEnumB : kotlin.Enum { + public constructor JavaEnumB() + public final override /*1*/ /*fake_override*/ val name: kotlin.String + public final override /*1*/ /*fake_override*/ val ordinal: kotlin.Int + protected final override /*1*/ /*fake_override*/ fun clone(): kotlin.Any + public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: JavaEnumB!): kotlin.Int + public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + protected/*protected and package*/ final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun finalize(): kotlin.Unit + public final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun getDeclaringClass(): java.lang.Class! + public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + // Static members + public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): JavaEnumB + public final /*synthesized*/ fun values(): kotlin.Array +} + +public final enum class KotlinEnumA : kotlin.Enum { + private constructor KotlinEnumA() + public final override /*1*/ /*fake_override*/ val name: kotlin.String + public final override /*1*/ /*fake_override*/ val ordinal: kotlin.Int + protected final override /*1*/ /*fake_override*/ fun clone(): kotlin.Any + public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: KotlinEnumA): kotlin.Int + public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + protected/*protected and package*/ final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun finalize(): kotlin.Unit + public final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun getDeclaringClass(): java.lang.Class! + public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + // Static members + public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): KotlinEnumA + public final /*synthesized*/ fun values(): kotlin.Array +} + +public final enum class KotlinEnumB : kotlin.Enum { + private constructor KotlinEnumB() + public final override /*1*/ /*fake_override*/ val name: kotlin.String + public final override /*1*/ /*fake_override*/ val ordinal: kotlin.Int + protected final override /*1*/ /*fake_override*/ fun clone(): kotlin.Any + public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: KotlinEnumB): kotlin.Int + public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + protected/*protected and package*/ final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun finalize(): kotlin.Unit + public final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun getDeclaringClass(): java.lang.Class! + public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + // Static members + public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): KotlinEnumB + public final /*synthesized*/ fun values(): kotlin.Array +} diff --git a/compiler/testData/diagnostics/tests/typeParameters/cannotHaveManyClassUpperBounds.kt b/compiler/testData/diagnostics/tests/typeParameters/cannotHaveManyClassUpperBounds.kt index 880904e5ca9..fcf7bee4652 100644 --- a/compiler/testData/diagnostics/tests/typeParameters/cannotHaveManyClassUpperBounds.kt +++ b/compiler/testData/diagnostics/tests/typeParameters/cannotHaveManyClassUpperBounds.kt @@ -12,7 +12,7 @@ fun f2() where T : C2, T : C3 {} fun f3() where T : C3, T : C2 {} enum class E1 -class A5<T> where T : C1, T : E1 +class A5 where T : C1, T : E1 object O1 class A6<T> where T : O1, T : C2 diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 2cf2c814a3a..39fb5ef84ef 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -7411,6 +7411,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("compareTwoDifferentEnums.kt") + public void testCompareTwoDifferentEnums() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/enum/compareTwoDifferentEnums.kt"); + doTest(fileName); + } + @TestMetadata("ConstructorCallFromOutside.kt") public void testConstructorCallFromOutside() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/enum/ConstructorCallFromOutside.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java index c10f475da25..d2c8ec6aace 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -7411,6 +7411,12 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing doTest(fileName); } + @TestMetadata("compareTwoDifferentEnums.kt") + public void testCompareTwoDifferentEnums() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/enum/compareTwoDifferentEnums.kt"); + doTest(fileName); + } + @TestMetadata("ConstructorCallFromOutside.kt") public void testConstructorCallFromOutside() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/enum/ConstructorCallFromOutside.kt"); diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/AbstractClassTypeConstructor.java b/core/descriptors/src/org/jetbrains/kotlin/types/AbstractClassTypeConstructor.java index 7da3630411c..1935bfd3100 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/AbstractClassTypeConstructor.java +++ b/core/descriptors/src/org/jetbrains/kotlin/types/AbstractClassTypeConstructor.java @@ -56,7 +56,7 @@ public abstract class AbstractClassTypeConstructor extends AbstractTypeConstruct @Override public final boolean isFinal() { ClassDescriptor descriptor = getDeclarationDescriptor(); - return descriptor.getModality() == Modality.FINAL && !descriptor.isExpect(); + return ModalityKt.isFinalClass(descriptor) && !descriptor.isExpect(); } @NotNull