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
This commit is contained in:
Alexander Udalov
2017-10-17 16:34:17 +02:00
parent 825aff7ac6
commit 6e410cb182
9 changed files with 136 additions and 35 deletions
@@ -3,10 +3,10 @@ enum class Direction {
NORTH, SOUTH, WEST, EAST
}
---------------------
<v0>: Direction NEW: magic[FAKE_INITIALIZER](NORTH,) -> <v0>
<v1>: Direction NEW: magic[FAKE_INITIALIZER](SOUTH,) -> <v1>
<v2>: Direction NEW: magic[FAKE_INITIALIZER](WEST,) -> <v2>
<v3>: Direction NEW: magic[FAKE_INITIALIZER](EAST) -> <v3>
<v0>: {<: Direction} NEW: magic[FAKE_INITIALIZER](NORTH,) -> <v0>
<v1>: {<: Direction} NEW: magic[FAKE_INITIALIZER](SOUTH,) -> <v1>
<v2>: {<: Direction} NEW: magic[FAKE_INITIALIZER](WEST,) -> <v2>
<v3>: {<: Direction} NEW: magic[FAKE_INITIALIZER](EAST) -> <v3>
=====================
== foo ==
fun foo(dir: Direction): Int {
@@ -20,31 +20,31 @@ fun foo(dir: Direction): Int {
return res
}
---------------------
<v0>: Direction NEW: magic[FAKE_INITIALIZER](dir: Direction) -> <v0>
<v14>: * NEW: magic[EXHAUSTIVE_WHEN_ELSE](when (dir) { Direction.NORTH -> res = 1 Direction.SOUTH -> res = 2 Direction.WEST -> res = 3 Direction.EAST -> res = 4 }) -> <v14>
dir <v1>: * NEW: r(dir) -> <v1>
NORTH <v2>: * NEW: r(NORTH) -> <v2>
Direction.NORTH <v2>: * COPY
Direction.NORTH <v3>: * NEW: magic[EQUALS_IN_WHEN_CONDITION](Direction.NORTH|<v1>, <v2>) -> <v3>
1 <v4>: Int NEW: r(1) -> <v4>
<v0>: {<: Direction} NEW: magic[FAKE_INITIALIZER](dir: Direction) -> <v0>
<v14>: * NEW: magic[EXHAUSTIVE_WHEN_ELSE](when (dir) { Direction.NORTH -> res = 1 Direction.SOUTH -> res = 2 Direction.WEST -> res = 3 Direction.EAST -> res = 4 }) -> <v14>
dir <v1>: * NEW: r(dir) -> <v1>
NORTH <v2>: * NEW: r(NORTH) -> <v2>
Direction.NORTH <v2>: * COPY
Direction.NORTH <v3>: * NEW: magic[EQUALS_IN_WHEN_CONDITION](Direction.NORTH|<v1>, <v2>) -> <v3>
1 <v4>: Int NEW: r(1) -> <v4>
res = 1 !<v15>: *
SOUTH <v5>: * NEW: r(SOUTH) -> <v5>
Direction.SOUTH <v5>: * COPY
Direction.SOUTH <v6>: * NEW: magic[EQUALS_IN_WHEN_CONDITION](Direction.SOUTH|<v1>, <v5>) -> <v6>
2 <v7>: Int NEW: r(2) -> <v7>
SOUTH <v5>: * NEW: r(SOUTH) -> <v5>
Direction.SOUTH <v5>: * COPY
Direction.SOUTH <v6>: * NEW: magic[EQUALS_IN_WHEN_CONDITION](Direction.SOUTH|<v1>, <v5>) -> <v6>
2 <v7>: Int NEW: r(2) -> <v7>
res = 2 !<v16>: *
WEST <v8>: * NEW: r(WEST) -> <v8>
Direction.WEST <v8>: * COPY
Direction.WEST <v9>: * NEW: magic[EQUALS_IN_WHEN_CONDITION](Direction.WEST|<v1>, <v8>) -> <v9>
3 <v10>: Int NEW: r(3) -> <v10>
WEST <v8>: * NEW: r(WEST) -> <v8>
Direction.WEST <v8>: * COPY
Direction.WEST <v9>: * NEW: magic[EQUALS_IN_WHEN_CONDITION](Direction.WEST|<v1>, <v8>) -> <v9>
3 <v10>: Int NEW: r(3) -> <v10>
res = 3 !<v17>: *
EAST <v11>: * NEW: r(EAST) -> <v11>
Direction.EAST <v11>: * COPY
Direction.EAST <v12>: * NEW: magic[EQUALS_IN_WHEN_CONDITION](Direction.EAST|<v1>, <v11>) -> <v12>
4 <v13>: Int NEW: r(4) -> <v13>
EAST <v11>: * NEW: r(EAST) -> <v11>
Direction.EAST <v11>: * COPY
Direction.EAST <v12>: * NEW: magic[EQUALS_IN_WHEN_CONDITION](Direction.EAST|<v1>, <v11>) -> <v12>
4 <v13>: Int NEW: r(4) -> <v13>
res = 4 !<v18>: *
when (dir) { Direction.NORTH -> res = 1 Direction.SOUTH -> res = 2 Direction.WEST -> res = 3 Direction.EAST -> res = 4 } <v19>: * NEW: merge(when (dir) { Direction.NORTH -> res = 1 Direction.SOUTH -> res = 2 Direction.WEST -> res = 3 Direction.EAST -> res = 4 }|!<v15>, !<v16>, !<v17>, !<v18>) -> <v19>
res <v20>: Int NEW: r(res) -> <v20>
when (dir) { Direction.NORTH -> res = 1 Direction.SOUTH -> res = 2 Direction.WEST -> res = 3 Direction.EAST -> res = 4 } <v19>: * NEW: merge(when (dir) { Direction.NORTH -> res = 1 Direction.SOUTH -> res = 2 Direction.WEST -> res = 3 Direction.EAST -> res = 4 }|!<v15>, !<v16>, !<v17>, !<v18>) -> <v19>
res <v20>: Int NEW: r(res) -> <v20>
return res !<v21>: *
{ val res: Int when (dir) { Direction.NORTH -> res = 1 Direction.SOUTH -> res = 2 Direction.WEST -> res = 3 Direction.EAST -> res = 4 } return res } !<v21>: * COPY
{ val res: Int when (dir) { Direction.NORTH -> res = 1 Direction.SOUTH -> res = 2 Direction.WEST -> res = 3 Direction.EAST -> res = 4 } return res } !<v21>: * COPY
=====================
@@ -10,8 +10,8 @@ enum class EE(val x: Int) {
---------------------
<v0>: Int NEW: magic[FAKE_INITIALIZER](val x: Int) -> <v0>
<v10>: EE.Companion NEW: magic[FAKE_INITIALIZER](companion object { fun foo() = 42 }) -> <v10>
<v1>: EE NEW: magic[FAKE_INITIALIZER](INSTANCE(Companion.foo()),) -> <v1>
<v5>: EE NEW: magic[FAKE_INITIALIZER](ANOTHER(foo());) -> <v5>
<v1>: {<: EE} NEW: magic[FAKE_INITIALIZER](INSTANCE(Companion.foo()),) -> <v1>
<v5>: {<: EE} NEW: magic[FAKE_INITIALIZER](ANOTHER(foo());) -> <v5>
<v7>: EE.Companion NEW: magic[IMPLICIT_RECEIVER](foo()) -> <v7>
Companion <v2>: EE.Companion NEW: r(Companion) -> <v2>
foo() <v3>: Int NEW: call(foo(), foo|<v2>) -> <v3>
@@ -10,10 +10,10 @@ enum class E(val x: Int) {
E1(0)
}
---------------------
<v0>: Int NEW: magic[FAKE_INITIALIZER](val x: Int) -> <v0>
<v1>: E NEW: magic[FAKE_INITIALIZER](E1(0)) -> <v1>
0 <v2>: Int NEW: r(0) -> <v2>
(0) <v3>: * NEW: call((0), <init>|<v2>) -> <v3>
<v0>: Int NEW: magic[FAKE_INITIALIZER](val x: Int) -> <v0>
<v1>: {<: E} NEW: magic[FAKE_INITIALIZER](E1(0)) -> <v1>
0 <v2>: Int NEW: r(0) -> <v2>
(0) <v3>: * NEW: call((0), <init>|<v2>) -> <v3>
=====================
== C ==
class C {
@@ -26,7 +26,7 @@ class C {
== foo ==
fun foo() = E1.x + O.y + C.z
---------------------
E1 <v0>: E NEW: r(E1) -> <v0>
E1 <v0>: {<: E} NEW: r(E1) -> <v0>
x <v1>: Int NEW: r(x|<v0>) -> <v1>
E1.x <v1>: Int COPY
O <v2>: O NEW: r(O) -> <v2>
@@ -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
@@ -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<JavaEnumA!> {
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<JavaEnumA!>!
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<JavaEnumA>
}
public final enum class JavaEnumB : kotlin.Enum<JavaEnumB!> {
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<JavaEnumB!>!
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<JavaEnumB>
}
public final enum class KotlinEnumA : kotlin.Enum<KotlinEnumA> {
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<KotlinEnumA!>!
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<KotlinEnumA>
}
public final enum class KotlinEnumB : kotlin.Enum<KotlinEnumB> {
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<KotlinEnumB!>!
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<KotlinEnumB>
}
@@ -12,7 +12,7 @@ fun <T> f2() where T : C2, T : <!ONLY_ONE_CLASS_BOUND_ALLOWED!>C3<!> {}
fun <T> f3() where T : C3, T : <!ONLY_ONE_CLASS_BOUND_ALLOWED!>C2<!> {}
enum class E1
class A5<<!CONFLICTING_UPPER_BOUNDS!>T<!>> where T : C1, T : <!ONLY_ONE_CLASS_BOUND_ALLOWED, FINAL_UPPER_BOUND!>E1<!>
class A5<T> where T : C1, T : <!ONLY_ONE_CLASS_BOUND_ALLOWED!>E1<!>
object O1
class A6<<!CONFLICTING_UPPER_BOUNDS!>T<!>> where T : <!FINAL_UPPER_BOUND!>O1<!>, T : <!ONLY_ONE_CLASS_BOUND_ALLOWED!>C2<!>
@@ -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");
@@ -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");
@@ -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