Gradually prohibit comparison of incompatible enums
#KT-22043 Fixed
This commit is contained in:
@@ -800,6 +800,8 @@ public interface Errors {
|
|||||||
|
|
||||||
DiagnosticFactory2<KtElement, KotlinType, KotlinType> INCOMPATIBLE_ENUM_COMPARISON =
|
DiagnosticFactory2<KtElement, KotlinType, KotlinType> INCOMPATIBLE_ENUM_COMPARISON =
|
||||||
DiagnosticFactory2.create(WARNING);
|
DiagnosticFactory2.create(WARNING);
|
||||||
|
DiagnosticFactory2<KtElement, KotlinType, KotlinType> INCOMPATIBLE_ENUM_COMPARISON_ERROR =
|
||||||
|
DiagnosticFactory2.create(ERROR);
|
||||||
|
|
||||||
DiagnosticFactory1<KtExpression, KotlinType> HAS_NEXT_MISSING = DiagnosticFactory1.create(ERROR);
|
DiagnosticFactory1<KtExpression, KotlinType> HAS_NEXT_MISSING = DiagnosticFactory1.create(ERROR);
|
||||||
DiagnosticFactory1<KtExpression, KotlinType> HAS_NEXT_FUNCTION_AMBIGUITY = DiagnosticFactory1.create(ERROR);
|
DiagnosticFactory1<KtExpression, KotlinType> HAS_NEXT_FUNCTION_AMBIGUITY = DiagnosticFactory1.create(ERROR);
|
||||||
|
|||||||
+1
@@ -741,6 +741,7 @@ public class DefaultErrorMessages {
|
|||||||
}, RENDER_TYPE, RENDER_TYPE);
|
}, RENDER_TYPE, RENDER_TYPE);
|
||||||
|
|
||||||
MAP.put(INCOMPATIBLE_ENUM_COMPARISON, "Comparison of incompatible enums ''{0}'' and ''{1}'' is always unsuccessful", RENDER_TYPE, RENDER_TYPE);
|
MAP.put(INCOMPATIBLE_ENUM_COMPARISON, "Comparison of incompatible enums ''{0}'' and ''{1}'' is always unsuccessful", RENDER_TYPE, RENDER_TYPE);
|
||||||
|
MAP.put(INCOMPATIBLE_ENUM_COMPARISON_ERROR, "Comparison of incompatible enums ''{0}'' and ''{1}'' is always unsuccessful", RENDER_TYPE, RENDER_TYPE);
|
||||||
|
|
||||||
MAP.put(SENSELESS_COMPARISON, "Condition ''{0}'' is always ''{1}''", ELEMENT_TEXT, TO_STRING);
|
MAP.put(SENSELESS_COMPARISON, "Condition ''{0}'' is always ''{1}''", ELEMENT_TEXT, TO_STRING);
|
||||||
MAP.put(SENSELESS_NULL_IN_WHEN, "Expression under 'when' is never equal to null");
|
MAP.put(SENSELESS_NULL_IN_WHEN, "Expression under 'when' is never equal to null");
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ import org.jetbrains.kotlin.resolve.calls.inference.CallHandle;
|
|||||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem;
|
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem;
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilderImpl;
|
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilderImpl;
|
||||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
|
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
|
||||||
import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt;
|
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@@ -41,11 +40,6 @@ public class TypeIntersector {
|
|||||||
return intersectTypes(new LinkedHashSet<>(Arrays.asList(typeA, typeB))) == null;
|
return intersectTypes(new LinkedHashSet<>(Arrays.asList(typeA, typeB))) == null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isIncompatibleEnums(@NotNull KotlinType typeA, @NotNull KotlinType typeB) {
|
|
||||||
if (!TypeUtilsKt.isEnum(typeA) || !TypeUtilsKt.isEnum(typeB)) return false;
|
|
||||||
return !typeA.getConstructor().equals(typeB.getConstructor());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public static KotlinType intersectTypes(@NotNull Collection<KotlinType> types) {
|
public static KotlinType intersectTypes(@NotNull Collection<KotlinType> types) {
|
||||||
assert !types.isEmpty() : "Attempting to intersect empty collection of types, this case should be dealt with on the call site.";
|
assert !types.isEmpty() : "Attempting to intersect empty collection of types, this case should be dealt with on the call site.";
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.types
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.config.LanguageFeature
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||||
|
import org.jetbrains.kotlin.diagnostics.Errors
|
||||||
|
import org.jetbrains.kotlin.psi.KtElement
|
||||||
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
|
import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.*
|
||||||
|
|
||||||
|
fun checkEnumsForCompatibility(context: ExpressionTypingContext, reportOn: KtElement, typeA: KotlinType, typeB: KotlinType) {
|
||||||
|
if (isIncompatibleEnums(typeA, typeB)) {
|
||||||
|
val diagnostic = if (context.languageVersionSettings.supportsFeature(LanguageFeature.ProhibitComparisonOfIncompatibleEnums)) {
|
||||||
|
Errors.INCOMPATIBLE_ENUM_COMPARISON_ERROR
|
||||||
|
} else {
|
||||||
|
Errors.INCOMPATIBLE_ENUM_COMPARISON
|
||||||
|
}
|
||||||
|
|
||||||
|
context.trace.report(diagnostic.on(reportOn, typeA, typeB))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isIncompatibleEnums(typeA: KotlinType, typeB: KotlinType): Boolean {
|
||||||
|
if (!typeA.isEnum() && !typeB.isEnum()) return false
|
||||||
|
if (TypeUtils.isNullableType(typeA) && TypeUtils.isNullableType(typeB)) return false
|
||||||
|
|
||||||
|
// TODO: remove this line once KT-30266 will be fixed
|
||||||
|
// For now, this check is needed as isSubClass contains bug wrt Nothing
|
||||||
|
if (typeA.isNothingOrNullableNothing() || typeB.isNothingOrNullableNothing()) return false
|
||||||
|
|
||||||
|
val representativeTypeA = typeA.representativeTypeForTypeParameter()
|
||||||
|
val representativeTypeB = typeB.representativeTypeForTypeParameter()
|
||||||
|
|
||||||
|
val classA = representativeTypeA.constructor.declarationDescriptor as? ClassDescriptor ?: return false
|
||||||
|
val classB = representativeTypeB.constructor.declarationDescriptor as? ClassDescriptor ?: return false
|
||||||
|
|
||||||
|
return !DescriptorUtils.isSubclass(classA, classB) && !DescriptorUtils.isSubclass(classB, classA)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun KotlinType.representativeTypeForTypeParameter(): KotlinType {
|
||||||
|
val descriptor = constructor.declarationDescriptor
|
||||||
|
return if (descriptor is TypeParameterDescriptor) descriptor.representativeUpperBound else this
|
||||||
|
}
|
||||||
+3
-3
@@ -1430,10 +1430,10 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
if (rightType != null) {
|
if (rightType != null) {
|
||||||
if (TypeIntersector.isIntersectionEmpty(leftType, rightType)) {
|
if (TypeIntersector.isIntersectionEmpty(leftType, rightType)) {
|
||||||
context.trace.report(EQUALITY_NOT_APPLICABLE.on(expression, expression.getOperationReference(), leftType, rightType));
|
context.trace.report(EQUALITY_NOT_APPLICABLE.on(expression, expression.getOperationReference(), leftType, rightType));
|
||||||
|
} else {
|
||||||
|
EnumCompatibilityCheckerKt.checkEnumsForCompatibility(context, expression, leftType, rightType);
|
||||||
}
|
}
|
||||||
else if (TypeIntersector.isIncompatibleEnums(leftType, rightType)) {
|
|
||||||
context.trace.report(INCOMPATIBLE_ENUM_COMPARISON.on(expression, leftType, rightType));
|
|
||||||
}
|
|
||||||
|
|
||||||
SenselessComparisonChecker.checkSenselessComparisonWithNull(
|
SenselessComparisonChecker.checkSenselessComparisonWithNull(
|
||||||
expression, left, right, context,
|
expression, left, right, context,
|
||||||
|
|||||||
+1
-3
@@ -684,9 +684,7 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TypeIntersector.isIncompatibleEnums(type, subjectType)) {
|
checkEnumsForCompatibility(context, reportErrorOn, type, subjectType)
|
||||||
context.trace.report(INCOMPATIBLE_ENUM_COMPARISON.on(reportErrorOn, subjectType, type))
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if the pattern is essentially a 'null' expression
|
// check if the pattern is essentially a 'null' expression
|
||||||
if (KotlinBuiltIns.isNullableNothing(type) && !TypeUtils.isNullableType(subjectType)) {
|
if (KotlinBuiltIns.isNullableNothing(type) && !TypeUtils.isNullableType(subjectType)) {
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
// !LANGUAGE: -ProhibitComparisonOfIncompatibleEnums
|
||||||
|
|
||||||
enum class E1 {
|
enum class E1 {
|
||||||
A, B
|
A, B
|
||||||
}
|
}
|
||||||
@@ -56,3 +58,88 @@ fun foo3(e1: Enum<E1>, e2: Enum<E2>, e: Enum<*>) {
|
|||||||
else -> {}
|
else -> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface MyInterface
|
||||||
|
open class MyOpenClass
|
||||||
|
|
||||||
|
fun foo4(e1: E1, i: MyInterface, c: MyOpenClass) {
|
||||||
|
<!INCOMPATIBLE_ENUM_COMPARISON!>e1 == i<!>
|
||||||
|
<!INCOMPATIBLE_ENUM_COMPARISON!>i == e1<!>
|
||||||
|
|
||||||
|
<!INCOMPATIBLE_ENUM_COMPARISON!>e1 == c<!>
|
||||||
|
<!INCOMPATIBLE_ENUM_COMPARISON!>c == e1<!>
|
||||||
|
|
||||||
|
when (e1) {
|
||||||
|
<!INCOMPATIBLE_ENUM_COMPARISON!>i<!> -> {}
|
||||||
|
<!INCOMPATIBLE_ENUM_COMPARISON!>c<!> -> {}
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class E3 : MyInterface { X, Y }
|
||||||
|
|
||||||
|
fun foo5(i: MyInterface, a: Any) {
|
||||||
|
E3.X == E3.Y
|
||||||
|
E3.X == i
|
||||||
|
E3.X == a
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo6(e1: E1?, e2: E2) {
|
||||||
|
<!SENSELESS_COMPARISON!>E1.A == null<!>
|
||||||
|
<!SENSELESS_COMPARISON!>null == E1.A<!>
|
||||||
|
e1 == null
|
||||||
|
null == e1
|
||||||
|
|
||||||
|
<!INCOMPATIBLE_ENUM_COMPARISON!>e1 == E2.A<!>
|
||||||
|
<!INCOMPATIBLE_ENUM_COMPARISON!>E2.A == e1<!>
|
||||||
|
<!INCOMPATIBLE_ENUM_COMPARISON!>e1 == e2<!>
|
||||||
|
<!INCOMPATIBLE_ENUM_COMPARISON!>e2 == e1<!>
|
||||||
|
|
||||||
|
<!SENSELESS_COMPARISON!>e2 == null<!>
|
||||||
|
<!SENSELESS_COMPARISON!>null == e2<!>
|
||||||
|
<!SENSELESS_COMPARISON!>E1.A == null<!>
|
||||||
|
<!SENSELESS_COMPARISON!>null == E1.A<!>
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo7(e1: E1?, e2: E2?) {
|
||||||
|
e1 == e2 // There should be an IDE-inspection for such cases
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> foo8(e1: E1?, e2: E2, t: T) {
|
||||||
|
e1 == t
|
||||||
|
t == e1
|
||||||
|
|
||||||
|
e2 == t
|
||||||
|
t == e2
|
||||||
|
|
||||||
|
E1.A == t
|
||||||
|
t == E1.A
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T, K> foo9(e1: E1?, e2: E2, t: T, k: K) where T : MyInterface, T : MyOpenClass, K : MyInterface {
|
||||||
|
<!INCOMPATIBLE_ENUM_COMPARISON!>e1 == t<!>
|
||||||
|
<!INCOMPATIBLE_ENUM_COMPARISON!>t == e1<!>
|
||||||
|
|
||||||
|
<!INCOMPATIBLE_ENUM_COMPARISON!>e2 == t<!>
|
||||||
|
<!INCOMPATIBLE_ENUM_COMPARISON!>t == e2<!>
|
||||||
|
|
||||||
|
<!INCOMPATIBLE_ENUM_COMPARISON!>E1.A == t<!>
|
||||||
|
<!INCOMPATIBLE_ENUM_COMPARISON!>t == E1.A<!>
|
||||||
|
|
||||||
|
<!INCOMPATIBLE_ENUM_COMPARISON!>E3.X == t<!>
|
||||||
|
|
||||||
|
E3.X == k
|
||||||
|
k == E3.X
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Inv<T>
|
||||||
|
|
||||||
|
enum class E4 : Inv<Int> { A }
|
||||||
|
|
||||||
|
fun foo10(e4: E4, invString: Inv<String>) {
|
||||||
|
e4 == invString
|
||||||
|
invString == e4
|
||||||
|
|
||||||
|
E4.A == invString
|
||||||
|
invString == E4.A
|
||||||
|
}
|
||||||
@@ -1,8 +1,15 @@
|
|||||||
package
|
package
|
||||||
|
|
||||||
public fun foo1(/*0*/ e1: E1, /*1*/ e2: E2): kotlin.Unit
|
public fun foo1(/*0*/ e1: E1, /*1*/ e2: E2): kotlin.Unit
|
||||||
|
public fun foo10(/*0*/ e4: E4, /*1*/ invString: Inv<kotlin.String>): kotlin.Unit
|
||||||
public fun foo2(/*0*/ e1: E1, /*1*/ e2: E2): kotlin.Unit
|
public fun foo2(/*0*/ e1: E1, /*1*/ e2: E2): kotlin.Unit
|
||||||
public fun foo3(/*0*/ e1: kotlin.Enum<E1>, /*1*/ e2: kotlin.Enum<E2>, /*2*/ e: kotlin.Enum<*>): kotlin.Unit
|
public fun foo3(/*0*/ e1: kotlin.Enum<E1>, /*1*/ e2: kotlin.Enum<E2>, /*2*/ e: kotlin.Enum<*>): kotlin.Unit
|
||||||
|
public fun foo4(/*0*/ e1: E1, /*1*/ i: MyInterface, /*2*/ c: MyOpenClass): kotlin.Unit
|
||||||
|
public fun foo5(/*0*/ i: MyInterface, /*1*/ a: kotlin.Any): kotlin.Unit
|
||||||
|
public fun foo6(/*0*/ e1: E1?, /*1*/ e2: E2): kotlin.Unit
|
||||||
|
public fun foo7(/*0*/ e1: E1?, /*1*/ e2: E2?): kotlin.Unit
|
||||||
|
public fun </*0*/ T> foo8(/*0*/ e1: E1?, /*1*/ e2: E2, /*2*/ t: T): kotlin.Unit
|
||||||
|
public fun </*0*/ T : MyInterface, /*1*/ K : MyInterface> foo9(/*0*/ e1: E1?, /*1*/ e2: E2, /*2*/ t: T, /*3*/ k: K): kotlin.Unit where T : MyOpenClass
|
||||||
|
|
||||||
public final enum class E1 : kotlin.Enum<E1> {
|
public final enum class E1 : kotlin.Enum<E1> {
|
||||||
enum entry A
|
enum entry A
|
||||||
@@ -45,3 +52,62 @@ public final enum class E2 : kotlin.Enum<E2> {
|
|||||||
public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): E2
|
public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): E2
|
||||||
public final /*synthesized*/ fun values(): kotlin.Array<E2>
|
public final /*synthesized*/ fun values(): kotlin.Array<E2>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final enum class E3 : kotlin.Enum<E3>, MyInterface {
|
||||||
|
enum entry X
|
||||||
|
|
||||||
|
enum entry Y
|
||||||
|
|
||||||
|
private constructor E3()
|
||||||
|
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: E3): kotlin.Int
|
||||||
|
public final override /*2*/ /*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<E3!>!
|
||||||
|
public final override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
|
||||||
|
// Static members
|
||||||
|
public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): E3
|
||||||
|
public final /*synthesized*/ fun values(): kotlin.Array<E3>
|
||||||
|
}
|
||||||
|
|
||||||
|
public final enum class E4 : kotlin.Enum<E4>, Inv<kotlin.Int> {
|
||||||
|
enum entry A
|
||||||
|
|
||||||
|
private constructor E4()
|
||||||
|
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: E4): kotlin.Int
|
||||||
|
public final override /*2*/ /*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<E4!>!
|
||||||
|
public final override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
|
||||||
|
// Static members
|
||||||
|
public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): E4
|
||||||
|
public final /*synthesized*/ fun values(): kotlin.Array<E4>
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface Inv</*0*/ T> {
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface MyInterface {
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
|
public open class MyOpenClass {
|
||||||
|
public constructor MyOpenClass()
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,145 @@
|
|||||||
|
// !LANGUAGE: +ProhibitComparisonOfIncompatibleEnums
|
||||||
|
|
||||||
|
enum class E1 {
|
||||||
|
A, B
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class E2 {
|
||||||
|
A, B
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo1(e1: E1, e2: E2) {
|
||||||
|
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>e1 == e2<!>
|
||||||
|
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>e1 != e2<!>
|
||||||
|
|
||||||
|
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>e1 == E2.A<!>
|
||||||
|
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>E1.B == e2<!>
|
||||||
|
|
||||||
|
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>E1.A == E2.B<!>
|
||||||
|
|
||||||
|
e1 == E1.A
|
||||||
|
E1.A == e1
|
||||||
|
e2 == E2.B
|
||||||
|
E2.B == e2
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo2(e1: E1, e2: E2) {
|
||||||
|
when (e1) {
|
||||||
|
E1.A -> {}
|
||||||
|
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>E2.A<!> -> {}
|
||||||
|
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>E2.B<!> -> {}
|
||||||
|
e1 -> {}
|
||||||
|
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>e2<!> -> {}
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo3(e1: Enum<E1>, e2: Enum<E2>, e: Enum<*>) {
|
||||||
|
e1 == e
|
||||||
|
e1 == e2
|
||||||
|
|
||||||
|
e1 == E1.A
|
||||||
|
e1 == E2.A
|
||||||
|
|
||||||
|
when (e1) {
|
||||||
|
e1 -> {}
|
||||||
|
e2 -> {}
|
||||||
|
e -> {}
|
||||||
|
E1.A -> {}
|
||||||
|
E2.A -> {}
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
|
|
||||||
|
when (e) {
|
||||||
|
e -> {}
|
||||||
|
e2 -> {}
|
||||||
|
E1.A -> {}
|
||||||
|
E2.A -> {}
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface MyInterface
|
||||||
|
open class MyOpenClass
|
||||||
|
|
||||||
|
fun foo4(e1: E1, i: MyInterface, c: MyOpenClass) {
|
||||||
|
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>e1 == i<!>
|
||||||
|
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>i == e1<!>
|
||||||
|
|
||||||
|
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>e1 == c<!>
|
||||||
|
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>c == e1<!>
|
||||||
|
|
||||||
|
when (e1) {
|
||||||
|
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>i<!> -> {}
|
||||||
|
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>c<!> -> {}
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class E3 : MyInterface { X, Y }
|
||||||
|
|
||||||
|
fun foo5(i: MyInterface, a: Any) {
|
||||||
|
E3.X == E3.Y
|
||||||
|
E3.X == i
|
||||||
|
E3.X == a
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo6(e1: E1?, e2: E2) {
|
||||||
|
<!SENSELESS_COMPARISON!>E1.A == null<!>
|
||||||
|
<!SENSELESS_COMPARISON!>null == E1.A<!>
|
||||||
|
e1 == null
|
||||||
|
null == e1
|
||||||
|
|
||||||
|
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>e1 == E2.A<!>
|
||||||
|
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>E2.A == e1<!>
|
||||||
|
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>e1 == e2<!>
|
||||||
|
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>e2 == e1<!>
|
||||||
|
|
||||||
|
<!SENSELESS_COMPARISON!>e2 == null<!>
|
||||||
|
<!SENSELESS_COMPARISON!>null == e2<!>
|
||||||
|
<!SENSELESS_COMPARISON!>E1.A == null<!>
|
||||||
|
<!SENSELESS_COMPARISON!>null == E1.A<!>
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo7(e1: E1?, e2: E2?) {
|
||||||
|
e1 == e2 // There should be an IDE-inspection for such cases
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> foo8(e1: E1?, e2: E2, t: T) {
|
||||||
|
e1 == t
|
||||||
|
t == e1
|
||||||
|
|
||||||
|
e2 == t
|
||||||
|
t == e2
|
||||||
|
|
||||||
|
E1.A == t
|
||||||
|
t == E1.A
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T, K> foo9(e1: E1?, e2: E2, t: T, k: K) where T : MyInterface, T : MyOpenClass, K : MyInterface {
|
||||||
|
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>e1 == t<!>
|
||||||
|
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>t == e1<!>
|
||||||
|
|
||||||
|
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>e2 == t<!>
|
||||||
|
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>t == e2<!>
|
||||||
|
|
||||||
|
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>E1.A == t<!>
|
||||||
|
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>t == E1.A<!>
|
||||||
|
|
||||||
|
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>E3.X == t<!>
|
||||||
|
|
||||||
|
E3.X == k
|
||||||
|
k == E3.X
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Inv<T>
|
||||||
|
|
||||||
|
enum class E4 : Inv<Int> { A }
|
||||||
|
|
||||||
|
fun foo10(e4: E4, invString: Inv<String>) {
|
||||||
|
e4 == invString
|
||||||
|
invString == e4
|
||||||
|
|
||||||
|
E4.A == invString
|
||||||
|
invString == E4.A
|
||||||
|
}
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public fun foo1(/*0*/ e1: E1, /*1*/ e2: E2): kotlin.Unit
|
||||||
|
public fun foo10(/*0*/ e4: E4, /*1*/ invString: Inv<kotlin.String>): kotlin.Unit
|
||||||
|
public fun foo2(/*0*/ e1: E1, /*1*/ e2: E2): kotlin.Unit
|
||||||
|
public fun foo3(/*0*/ e1: kotlin.Enum<E1>, /*1*/ e2: kotlin.Enum<E2>, /*2*/ e: kotlin.Enum<*>): kotlin.Unit
|
||||||
|
public fun foo4(/*0*/ e1: E1, /*1*/ i: MyInterface, /*2*/ c: MyOpenClass): kotlin.Unit
|
||||||
|
public fun foo5(/*0*/ i: MyInterface, /*1*/ a: kotlin.Any): kotlin.Unit
|
||||||
|
public fun foo6(/*0*/ e1: E1?, /*1*/ e2: E2): kotlin.Unit
|
||||||
|
public fun foo7(/*0*/ e1: E1?, /*1*/ e2: E2?): kotlin.Unit
|
||||||
|
public fun </*0*/ T> foo8(/*0*/ e1: E1?, /*1*/ e2: E2, /*2*/ t: T): kotlin.Unit
|
||||||
|
public fun </*0*/ T : MyInterface, /*1*/ K : MyInterface> foo9(/*0*/ e1: E1?, /*1*/ e2: E2, /*2*/ t: T, /*3*/ k: K): kotlin.Unit where T : MyOpenClass
|
||||||
|
|
||||||
|
public final enum class E1 : kotlin.Enum<E1> {
|
||||||
|
enum entry A
|
||||||
|
|
||||||
|
enum entry B
|
||||||
|
|
||||||
|
private constructor E1()
|
||||||
|
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: E1): 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<E1!>!
|
||||||
|
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): E1
|
||||||
|
public final /*synthesized*/ fun values(): kotlin.Array<E1>
|
||||||
|
}
|
||||||
|
|
||||||
|
public final enum class E2 : kotlin.Enum<E2> {
|
||||||
|
enum entry A
|
||||||
|
|
||||||
|
enum entry B
|
||||||
|
|
||||||
|
private constructor E2()
|
||||||
|
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: E2): 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<E2!>!
|
||||||
|
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): E2
|
||||||
|
public final /*synthesized*/ fun values(): kotlin.Array<E2>
|
||||||
|
}
|
||||||
|
|
||||||
|
public final enum class E3 : kotlin.Enum<E3>, MyInterface {
|
||||||
|
enum entry X
|
||||||
|
|
||||||
|
enum entry Y
|
||||||
|
|
||||||
|
private constructor E3()
|
||||||
|
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: E3): kotlin.Int
|
||||||
|
public final override /*2*/ /*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<E3!>!
|
||||||
|
public final override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
|
||||||
|
// Static members
|
||||||
|
public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): E3
|
||||||
|
public final /*synthesized*/ fun values(): kotlin.Array<E3>
|
||||||
|
}
|
||||||
|
|
||||||
|
public final enum class E4 : kotlin.Enum<E4>, Inv<kotlin.Int> {
|
||||||
|
enum entry A
|
||||||
|
|
||||||
|
private constructor E4()
|
||||||
|
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: E4): kotlin.Int
|
||||||
|
public final override /*2*/ /*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<E4!>!
|
||||||
|
public final override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
|
||||||
|
// Static members
|
||||||
|
public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): E4
|
||||||
|
public final /*synthesized*/ fun values(): kotlin.Array<E4>
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface Inv</*0*/ T> {
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface MyInterface {
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
|
public open class MyOpenClass {
|
||||||
|
public constructor MyOpenClass()
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
@@ -6943,6 +6943,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
|||||||
runTest("compiler/testData/diagnostics/tests/enum/incompatibleEnums.kt");
|
runTest("compiler/testData/diagnostics/tests/enum/incompatibleEnums.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("incompatibleEnums_1_4.kt")
|
||||||
|
public void testIncompatibleEnums_1_4() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/enum/incompatibleEnums_1_4.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("inheritFromEnumEntry.kt")
|
@TestMetadata("inheritFromEnumEntry.kt")
|
||||||
public void testInheritFromEnumEntry() throws Exception {
|
public void testInheritFromEnumEntry() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/tests/enum/inheritFromEnumEntry.kt");
|
runTest("compiler/testData/diagnostics/tests/enum/inheritFromEnumEntry.kt");
|
||||||
|
|||||||
Generated
+5
@@ -6938,6 +6938,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
|
|||||||
runTest("compiler/testData/diagnostics/tests/enum/incompatibleEnums.kt");
|
runTest("compiler/testData/diagnostics/tests/enum/incompatibleEnums.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("incompatibleEnums_1_4.kt")
|
||||||
|
public void testIncompatibleEnums_1_4() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/enum/incompatibleEnums_1_4.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("inheritFromEnumEntry.kt")
|
@TestMetadata("inheritFromEnumEntry.kt")
|
||||||
public void testInheritFromEnumEntry() throws Exception {
|
public void testInheritFromEnumEntry() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/tests/enum/inheritFromEnumEntry.kt");
|
runTest("compiler/testData/diagnostics/tests/enum/inheritFromEnumEntry.kt");
|
||||||
|
|||||||
@@ -101,6 +101,7 @@ enum class LanguageFeature(
|
|||||||
ProhibitRepeatedUseSiteTargetAnnotations(KOTLIN_1_4, kind = BUG_FIX),
|
ProhibitRepeatedUseSiteTargetAnnotations(KOTLIN_1_4, kind = BUG_FIX),
|
||||||
ProhibitUseSiteTargetAnnotationsOnSuperTypes(KOTLIN_1_4, kind = BUG_FIX),
|
ProhibitUseSiteTargetAnnotationsOnSuperTypes(KOTLIN_1_4, kind = BUG_FIX),
|
||||||
ProhibitTypeParametersInClassLiteralsInAnnotationArguments(KOTLIN_1_4, kind = BUG_FIX),
|
ProhibitTypeParametersInClassLiteralsInAnnotationArguments(KOTLIN_1_4, kind = BUG_FIX),
|
||||||
|
ProhibitComparisonOfIncompatibleEnums(KOTLIN_1_4, kind = BUG_FIX),
|
||||||
|
|
||||||
ProperVisibilityForCompanionObjectInstanceField(sinceVersion = null, kind = BUG_FIX),
|
ProperVisibilityForCompanionObjectInstanceField(sinceVersion = null, kind = BUG_FIX),
|
||||||
// Temporarily disabled, see KT-27084/KT-22379
|
// Temporarily disabled, see KT-27084/KT-22379
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ fun KotlinType.supertypes(): Collection<KotlinType> = TypeUtils.getAllSupertypes
|
|||||||
|
|
||||||
fun KotlinType.isNothing(): Boolean = KotlinBuiltIns.isNothing(this)
|
fun KotlinType.isNothing(): Boolean = KotlinBuiltIns.isNothing(this)
|
||||||
fun KotlinType.isNullableNothing(): Boolean = KotlinBuiltIns.isNullableNothing(this)
|
fun KotlinType.isNullableNothing(): Boolean = KotlinBuiltIns.isNullableNothing(this)
|
||||||
|
fun KotlinType.isNothingOrNullableNothing(): Boolean = KotlinBuiltIns.isNothingOrNullableNothing(this)
|
||||||
fun KotlinType.isUnit(): Boolean = KotlinBuiltIns.isUnit(this)
|
fun KotlinType.isUnit(): Boolean = KotlinBuiltIns.isUnit(this)
|
||||||
fun KotlinType.isAnyOrNullableAny(): Boolean = KotlinBuiltIns.isAnyOrNullableAny(this)
|
fun KotlinType.isAnyOrNullableAny(): Boolean = KotlinBuiltIns.isAnyOrNullableAny(this)
|
||||||
fun KotlinType.isNullableAny(): Boolean = KotlinBuiltIns.isNullableAny(this)
|
fun KotlinType.isNullableAny(): Boolean = KotlinBuiltIns.isNullableAny(this)
|
||||||
|
|||||||
Reference in New Issue
Block a user