diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java index 5246755f9c8..ac52890d758 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java @@ -31681,6 +31681,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti runTest("compiler/testData/diagnostics/tests/when/NonExhaustiveWarningNull.kt"); } + @Test + @TestMetadata("nonExhaustiveWhenStatement_1_5.kt") + public void testNonExhaustiveWhenStatement_1_5() throws Exception { + runTest("compiler/testData/diagnostics/tests/when/nonExhaustiveWhenStatement_1_5.kt"); + } + @Test @TestMetadata("nonExhaustiveWhenStatement_1_6.kt") public void testNonExhaustiveWhenStatement_1_6() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java index 199bb8b83d6..84a41d5e0ce 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java @@ -31681,6 +31681,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac runTest("compiler/testData/diagnostics/tests/when/NonExhaustiveWarningNull.kt"); } + @Test + @TestMetadata("nonExhaustiveWhenStatement_1_5.kt") + public void testNonExhaustiveWhenStatement_1_5() throws Exception { + runTest("compiler/testData/diagnostics/tests/when/nonExhaustiveWhenStatement_1_5.kt"); + } + @Test @TestMetadata("nonExhaustiveWhenStatement_1_6.kt") public void testNonExhaustiveWhenStatement_1_6() throws Exception { diff --git a/compiler/frontend/cfg/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProviderImpl.kt b/compiler/frontend/cfg/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProviderImpl.kt index e093aa59958..5a5aecbe244 100644 --- a/compiler/frontend/cfg/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProviderImpl.kt +++ b/compiler/frontend/cfg/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProviderImpl.kt @@ -37,10 +37,8 @@ import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject import org.jetbrains.kotlin.psi.psiUtil.forEachDescendantOfType +import org.jetbrains.kotlin.resolve.* import org.jetbrains.kotlin.resolve.BindingContext.* -import org.jetbrains.kotlin.resolve.BindingTrace -import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils -import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.bindingContextUtil.getEnclosingDescriptor import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsExpression import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsResultOfLambda @@ -56,7 +54,6 @@ import org.jetbrains.kotlin.resolve.calls.util.isSingleUnderscore import org.jetbrains.kotlin.resolve.checkers.PlatformDiagnosticSuppressor import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyExternal import org.jetbrains.kotlin.resolve.descriptorUtil.module -import org.jetbrains.kotlin.resolve.indexOrMinusOne import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeUtils.* @@ -1025,20 +1022,16 @@ class ControlFlowInformationProviderImpl private constructor( } continue } - if (!usedAsExpression && missingCases.isNotEmpty()) { - val kind = when { - WhenChecker.getClassDescriptorOfTypeIfSealed(subjectType) != null -> AlgebraicTypeKind.Sealed - WhenChecker.getClassDescriptorOfTypeIfEnum(subjectType) != null -> AlgebraicTypeKind.Enum - subjectType?.isBooleanOrNullableBoolean() == true -> AlgebraicTypeKind.Boolean - else -> null - } + if (!usedAsExpression) { - if (kind != null) { - if (languageVersionSettings.supportsFeature(LanguageFeature.ProhibitNonExhaustiveWhenOnAlgebraicTypes)) { - trace.report(NO_ELSE_IN_WHEN.on(element, missingCases)) - } else { - trace.report(NON_EXHAUSTIVE_WHEN_STATEMENT.on(element, kind.displayName, missingCases)) - } + } + if (!usedAsExpression) { + if (languageVersionSettings.supportsFeature(LanguageFeature.WarnAboutNonExhaustiveWhenOnAlgebraicTypes)) { + // report warnings on all non-exhaustive when's with algebraic subject + checkExhaustiveWhenStatement(subjectType, element, missingCases) + } else { + // report info if subject is sealed class and warning if it is enum + checkWhenStatement(subjectType, element, context) } } } @@ -1046,6 +1039,49 @@ class ControlFlowInformationProviderImpl private constructor( } } + private fun checkWhenStatement( + subjectType: KotlinType?, + element: KtWhenExpression, + context: BindingContext + ) { + val enumClassDescriptor = WhenChecker.getClassDescriptorOfTypeIfEnum(subjectType) + if (enumClassDescriptor != null) { + val enumMissingCases = WhenChecker.getEnumMissingCases(element, context, enumClassDescriptor) + if (enumMissingCases.isNotEmpty()) { + trace.report(NON_EXHAUSTIVE_WHEN.on(element, enumMissingCases)) + } + } + val sealedClassDescriptor = WhenChecker.getClassDescriptorOfTypeIfSealed(subjectType) + if (sealedClassDescriptor != null) { + val sealedMissingCases = WhenChecker.getSealedMissingCases(element, context, sealedClassDescriptor) + if (sealedMissingCases.isNotEmpty()) { + trace.report(NON_EXHAUSTIVE_WHEN_ON_SEALED_CLASS.on(element, sealedMissingCases)) + } + } + } + + private fun checkExhaustiveWhenStatement( + subjectType: KotlinType?, + element: KtWhenExpression, + missingCases: List + ) { + if (missingCases.isEmpty()) return + val kind = when { + WhenChecker.getClassDescriptorOfTypeIfSealed(subjectType) != null -> AlgebraicTypeKind.Sealed + WhenChecker.getClassDescriptorOfTypeIfEnum(subjectType) != null -> AlgebraicTypeKind.Enum + subjectType?.isBooleanOrNullableBoolean() == true -> AlgebraicTypeKind.Boolean + else -> null + } + + if (kind != null) { + if (languageVersionSettings.supportsFeature(LanguageFeature.ProhibitNonExhaustiveWhenOnAlgebraicTypes)) { + trace.report(NO_ELSE_IN_WHEN.on(element, missingCases)) + } else { + trace.report(NON_EXHAUSTIVE_WHEN_STATEMENT.on(element, kind.displayName, missingCases)) + } + } + } + private enum class AlgebraicTypeKind(val displayName: String) { Sealed("sealed class/interface"), Enum("enum"), diff --git a/compiler/testData/diagnostics/tests/j+k/kt2619.kt b/compiler/testData/diagnostics/tests/j+k/kt2619.kt index f5019e77cf0..fe7f286ffc8 100644 --- a/compiler/testData/diagnostics/tests/j+k/kt2619.kt +++ b/compiler/testData/diagnostics/tests/j+k/kt2619.kt @@ -1,5 +1,6 @@ // FIR_IDENTICAL -//FILE: foo.kt +// LANGUAGE: +WarnAboutNonExhaustiveWhenOnAlgebraicTypes +// FILE: foo.kt fun main() { val c: Type when (c) { diff --git a/compiler/testData/diagnostics/tests/reassignment/when.kt b/compiler/testData/diagnostics/tests/reassignment/when.kt index 550507f09f4..1e4eac0a127 100644 --- a/compiler/testData/diagnostics/tests/reassignment/when.kt +++ b/compiler/testData/diagnostics/tests/reassignment/when.kt @@ -1,4 +1,5 @@ // FIR_IDENTICAL +// LANGUAGE: +WarnAboutNonExhaustiveWhenOnAlgebraicTypes // !DIAGNOSTICS: -UNUSED_VALUE fun foo(f: Boolean): Int { diff --git a/compiler/testData/diagnostics/tests/smartCasts/propertyAsCondition.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/propertyAsCondition.fir.kt index cccaea15671..59212d7bf61 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/propertyAsCondition.fir.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/propertyAsCondition.fir.kt @@ -1,3 +1,4 @@ +// LANGUAGE: +WarnAboutNonExhaustiveWhenOnAlgebraicTypes // See also: KT-11998 data class My(val x: Boolean?) diff --git a/compiler/testData/diagnostics/tests/smartCasts/propertyAsCondition.kt b/compiler/testData/diagnostics/tests/smartCasts/propertyAsCondition.kt index 0597379cea1..a630589fcfb 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/propertyAsCondition.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/propertyAsCondition.kt @@ -1,3 +1,4 @@ +// LANGUAGE: +WarnAboutNonExhaustiveWhenOnAlgebraicTypes // See also: KT-11998 data class My(val x: Boolean?) diff --git a/compiler/testData/diagnostics/tests/when/ExhaustiveValOverConditionalInit.fir.kt b/compiler/testData/diagnostics/tests/when/ExhaustiveValOverConditionalInit.fir.kt index af34594898a..cf3175bb2a2 100644 --- a/compiler/testData/diagnostics/tests/when/ExhaustiveValOverConditionalInit.fir.kt +++ b/compiler/testData/diagnostics/tests/when/ExhaustiveValOverConditionalInit.fir.kt @@ -1,3 +1,4 @@ +// LANGUAGE: +WarnAboutNonExhaustiveWhenOnAlgebraicTypes /* * KOTLIN DIAGNOSTICS SPEC TEST (NEGATIVE) * diff --git a/compiler/testData/diagnostics/tests/when/ExhaustiveValOverConditionalInit.kt b/compiler/testData/diagnostics/tests/when/ExhaustiveValOverConditionalInit.kt index 7203d4d45c4..aa6ea32d0fb 100644 --- a/compiler/testData/diagnostics/tests/when/ExhaustiveValOverConditionalInit.kt +++ b/compiler/testData/diagnostics/tests/when/ExhaustiveValOverConditionalInit.kt @@ -1,3 +1,4 @@ +// LANGUAGE: +WarnAboutNonExhaustiveWhenOnAlgebraicTypes /* * KOTLIN DIAGNOSTICS SPEC TEST (NEGATIVE) * diff --git a/compiler/testData/diagnostics/tests/when/ExhaustiveVarOverConditionalInit.fir.kt b/compiler/testData/diagnostics/tests/when/ExhaustiveVarOverConditionalInit.fir.kt index 81c370ef2b3..84c24b1a14c 100644 --- a/compiler/testData/diagnostics/tests/when/ExhaustiveVarOverConditionalInit.fir.kt +++ b/compiler/testData/diagnostics/tests/when/ExhaustiveVarOverConditionalInit.fir.kt @@ -1,3 +1,4 @@ +// LANGUAGE: +WarnAboutNonExhaustiveWhenOnAlgebraicTypes /* * KOTLIN DIAGNOSTICS SPEC TEST (NEGATIVE) * diff --git a/compiler/testData/diagnostics/tests/when/ExhaustiveVarOverConditionalInit.kt b/compiler/testData/diagnostics/tests/when/ExhaustiveVarOverConditionalInit.kt index 88bb89dba7a..9ec0651a878 100644 --- a/compiler/testData/diagnostics/tests/when/ExhaustiveVarOverConditionalInit.kt +++ b/compiler/testData/diagnostics/tests/when/ExhaustiveVarOverConditionalInit.kt @@ -1,3 +1,4 @@ +// LANGUAGE: +WarnAboutNonExhaustiveWhenOnAlgebraicTypes /* * KOTLIN DIAGNOSTICS SPEC TEST (NEGATIVE) * diff --git a/compiler/testData/diagnostics/tests/when/NonExhaustiveWarning.kt b/compiler/testData/diagnostics/tests/when/NonExhaustiveWarning.kt index 4ab8accdd14..186b261853c 100644 --- a/compiler/testData/diagnostics/tests/when/NonExhaustiveWarning.kt +++ b/compiler/testData/diagnostics/tests/when/NonExhaustiveWarning.kt @@ -1,4 +1,5 @@ // FIR_IDENTICAL +// LANGUAGE: +WarnAboutNonExhaustiveWhenOnAlgebraicTypes /* * KOTLIN DIAGNOSTICS SPEC TEST (NEGATIVE) * diff --git a/compiler/testData/diagnostics/tests/when/NonExhaustiveWarningForSealedClass.fir.kt b/compiler/testData/diagnostics/tests/when/NonExhaustiveWarningForSealedClass.fir.kt index a954203c162..405dfb5e8cf 100644 --- a/compiler/testData/diagnostics/tests/when/NonExhaustiveWarningForSealedClass.fir.kt +++ b/compiler/testData/diagnostics/tests/when/NonExhaustiveWarningForSealedClass.fir.kt @@ -1,3 +1,4 @@ +// LANGUAGE: +WarnAboutNonExhaustiveWhenOnAlgebraicTypes /* * KOTLIN DIAGNOSTICS SPEC TEST (NEGATIVE) * diff --git a/compiler/testData/diagnostics/tests/when/NonExhaustiveWarningForSealedClass.kt b/compiler/testData/diagnostics/tests/when/NonExhaustiveWarningForSealedClass.kt index dad73acc4d0..a4891879ee9 100644 --- a/compiler/testData/diagnostics/tests/when/NonExhaustiveWarningForSealedClass.kt +++ b/compiler/testData/diagnostics/tests/when/NonExhaustiveWarningForSealedClass.kt @@ -1,3 +1,4 @@ +// LANGUAGE: +WarnAboutNonExhaustiveWhenOnAlgebraicTypes /* * KOTLIN DIAGNOSTICS SPEC TEST (NEGATIVE) * diff --git a/compiler/testData/diagnostics/tests/when/NonExhaustiveWarningNull.kt b/compiler/testData/diagnostics/tests/when/NonExhaustiveWarningNull.kt index ef5adf6f92e..c9557bcc556 100644 --- a/compiler/testData/diagnostics/tests/when/NonExhaustiveWarningNull.kt +++ b/compiler/testData/diagnostics/tests/when/NonExhaustiveWarningNull.kt @@ -1,4 +1,5 @@ // FIR_IDENTICAL +// LANGUAGE: +WarnAboutNonExhaustiveWhenOnAlgebraicTypes /* * KOTLIN DIAGNOSTICS SPEC TEST (NEGATIVE) * diff --git a/compiler/testData/diagnostics/tests/when/nonExhaustiveWhenStatement_1_5.fir.kt b/compiler/testData/diagnostics/tests/when/nonExhaustiveWhenStatement_1_5.fir.kt new file mode 100644 index 00000000000..b21bf2e83ae --- /dev/null +++ b/compiler/testData/diagnostics/tests/when/nonExhaustiveWhenStatement_1_5.fir.kt @@ -0,0 +1,154 @@ +// !LANGUAGE: -WarnAboutNonExhaustiveWhenOnAlgebraicTypes -ProhibitNonExhaustiveWhenOnAlgebraicTypes + +enum class SomeEnum { + A, B +} + +sealed class Base { + class A : Base() + class B : Base() +} + +sealed interface IBase { + interface A : IBase + interface B : IBase +} + +// ------------------ not null ------------------ + +fun test_1(x: SomeEnum) { + when (x) { + SomeEnum.A -> "" + } +} + +fun test_2(x: Base) { + when (x) { + is Base.A -> "" + } +} + +fun test_3(x: IBase) { + when (x) { + is IBase.A -> "" + } +} + +fun test_4(x: Boolean) { + when (x) { + true -> "" + } +} + +// ------------------ nullable ------------------ + +fun test_5(x: SomeEnum?) { + when (x) { + SomeEnum.A -> "" + SomeEnum.B -> "" + } + + when (x) { + SomeEnum.A -> "" + null -> "" + } +} + +fun test_6(x: Base?) { + when (x) { + is Base.A -> "" + is Base.B -> "" + } + + when (x) { + is Base.A -> "" + null -> "" + } +} + +fun test_7(x: IBase?) { + when (x) { + is IBase.A -> "" + is IBase.B -> "" + } + when (x) { + is IBase.A -> "" + null -> "" + } +} + +fun test_8(x: Boolean?) { + when (x) { + true -> "" + false -> "" + } + + when (x) { + true -> "" + null -> "" + } +} + +// ------------------ with else ------------------ + +fun test_9(x: SomeEnum?) { + when (x) { + SomeEnum.A -> "" + else -> "" + } +} + +fun test_10(x: Base?) { + when (x) { + is Base.A -> "" + else -> "" + } +} + +fun test_11(x: IBase?) { + when (x) { + is IBase.A -> "" + else -> "" + } +} + +fun test_12(x: Boolean?) { + when (x) { + true -> "" + else -> "" + } +} + +// ------------------ exhaustive ------------------ + +fun test_13(x: SomeEnum?) { + when (x) { + SomeEnum.A -> "" + SomeEnum.B -> "" + null -> "" + } +} + +fun test_14(x: Base?) { + when (x) { + is Base.A -> "" + is Base.B -> "" + null -> "" + } +} + +fun test_15(x: IBase?) { + when (x) { + is IBase.A -> "" + is IBase.B -> "" + null -> "" + } +} + +fun test_16(x: Boolean?) { + when (x) { + true -> "" + false -> "" + null -> "" + } +} diff --git a/compiler/testData/diagnostics/tests/when/nonExhaustiveWhenStatement_1_5.kt b/compiler/testData/diagnostics/tests/when/nonExhaustiveWhenStatement_1_5.kt new file mode 100644 index 00000000000..c4c88c69d72 --- /dev/null +++ b/compiler/testData/diagnostics/tests/when/nonExhaustiveWhenStatement_1_5.kt @@ -0,0 +1,154 @@ +// !LANGUAGE: -WarnAboutNonExhaustiveWhenOnAlgebraicTypes -ProhibitNonExhaustiveWhenOnAlgebraicTypes + +enum class SomeEnum { + A, B +} + +sealed class Base { + class A : Base() + class B : Base() +} + +sealed interface IBase { + interface A : IBase + interface B : IBase +} + +// ------------------ not null ------------------ + +fun test_1(x: SomeEnum) { + when (x) { + SomeEnum.A -> "" + } +} + +fun test_2(x: Base) { + when (x) { + is Base.A -> "" + } +} + +fun test_3(x: IBase) { + when (x) { + is IBase.A -> "" + } +} + +fun test_4(x: Boolean) { + when (x) { + true -> "" + } +} + +// ------------------ nullable ------------------ + +fun test_5(x: SomeEnum?) { + when (x) { + SomeEnum.A -> "" + SomeEnum.B -> "" + } + + when (x) { + SomeEnum.A -> "" + null -> "" + } +} + +fun test_6(x: Base?) { + when (x) { + is Base.A -> "" + is Base.B -> "" + } + + when (x) { + is Base.A -> "" + null -> "" + } +} + +fun test_7(x: IBase?) { + when (x) { + is IBase.A -> "" + is IBase.B -> "" + } + when (x) { + is IBase.A -> "" + null -> "" + } +} + +fun test_8(x: Boolean?) { + when (x) { + true -> "" + false -> "" + } + + when (x) { + true -> "" + null -> "" + } +} + +// ------------------ with else ------------------ + +fun test_9(x: SomeEnum?) { + when (x) { + SomeEnum.A -> "" + else -> "" + } +} + +fun test_10(x: Base?) { + when (x) { + is Base.A -> "" + else -> "" + } +} + +fun test_11(x: IBase?) { + when (x) { + is IBase.A -> "" + else -> "" + } +} + +fun test_12(x: Boolean?) { + when (x) { + true -> "" + else -> "" + } +} + +// ------------------ exhaustive ------------------ + +fun test_13(x: SomeEnum?) { + when (x) { + SomeEnum.A -> "" + SomeEnum.B -> "" + null -> "" + } +} + +fun test_14(x: Base?) { + when (x) { + is Base.A -> "" + is Base.B -> "" + null -> "" + } +} + +fun test_15(x: IBase?) { + when (x) { + is IBase.A -> "" + is IBase.B -> "" + null -> "" + } +} + +fun test_16(x: Boolean?) { + when (x) { + true -> "" + false -> "" + null -> "" + } +} diff --git a/compiler/testData/diagnostics/tests/when/nonExhaustiveWhenStatement_1_5.txt b/compiler/testData/diagnostics/tests/when/nonExhaustiveWhenStatement_1_5.txt new file mode 100644 index 00000000000..4357927d632 --- /dev/null +++ b/compiler/testData/diagnostics/tests/when/nonExhaustiveWhenStatement_1_5.txt @@ -0,0 +1,78 @@ +package + +public fun test_1(/*0*/ x: SomeEnum): kotlin.Unit +public fun test_10(/*0*/ x: Base?): kotlin.Unit +public fun test_11(/*0*/ x: IBase?): kotlin.Unit +public fun test_12(/*0*/ x: kotlin.Boolean?): kotlin.Unit +public fun test_13(/*0*/ x: SomeEnum?): kotlin.Unit +public fun test_14(/*0*/ x: Base?): kotlin.Unit +public fun test_15(/*0*/ x: IBase?): kotlin.Unit +public fun test_16(/*0*/ x: kotlin.Boolean?): kotlin.Unit +public fun test_2(/*0*/ x: Base): kotlin.Unit +public fun test_3(/*0*/ x: IBase): kotlin.Unit +public fun test_4(/*0*/ x: kotlin.Boolean): kotlin.Unit +public fun test_5(/*0*/ x: SomeEnum?): kotlin.Unit +public fun test_6(/*0*/ x: Base?): kotlin.Unit +public fun test_7(/*0*/ x: IBase?): kotlin.Unit +public fun test_8(/*0*/ x: kotlin.Boolean?): kotlin.Unit +public fun test_9(/*0*/ x: SomeEnum?): kotlin.Unit + +public sealed class Base { + protected constructor Base() + 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 final class A : Base { + public constructor A() + 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 final class B : Base { + public constructor B() + 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 sealed interface IBase { + 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 A : IBase { + 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 B : IBase { + 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 final enum class SomeEnum : kotlin.Enum { + enum entry A + + enum entry B + + private constructor SomeEnum() + 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: SomeEnum): 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): SomeEnum + public final /*synthesized*/ fun values(): kotlin.Array +} diff --git a/compiler/testData/diagnostics/tests/when/nonExhaustiveWhenStatement_1_6.kt b/compiler/testData/diagnostics/tests/when/nonExhaustiveWhenStatement_1_6.kt index e61cf172d20..fb1dbd7efa4 100644 --- a/compiler/testData/diagnostics/tests/when/nonExhaustiveWhenStatement_1_6.kt +++ b/compiler/testData/diagnostics/tests/when/nonExhaustiveWhenStatement_1_6.kt @@ -1,5 +1,5 @@ // FIR_IDENTICAL -// !LANGUAGE: -ProhibitNonExhaustiveWhenOnAlgebraicTypes +// !LANGUAGE: +WarnAboutNonExhaustiveWhenOnAlgebraicTypes -ProhibitNonExhaustiveWhenOnAlgebraicTypes enum class SomeEnum { A, B diff --git a/compiler/testData/diagnostics/tests/when/nonExhaustiveWhenStatement_1_7.kt b/compiler/testData/diagnostics/tests/when/nonExhaustiveWhenStatement_1_7.kt index 64fbe139faa..e1f0a7e4e49 100644 --- a/compiler/testData/diagnostics/tests/when/nonExhaustiveWhenStatement_1_7.kt +++ b/compiler/testData/diagnostics/tests/when/nonExhaustiveWhenStatement_1_7.kt @@ -1,5 +1,5 @@ // FIR_IDENTICAL -// !LANGUAGE: +ProhibitNonExhaustiveWhenOnAlgebraicTypes +// !LANGUAGE: +WarnAboutNonExhaustiveWhenOnAlgebraicTypes +ProhibitNonExhaustiveWhenOnAlgebraicTypes enum class SomeEnum { A, B diff --git a/compiler/testData/diagnostics/testsWithStdLib/when/kt10192.kt b/compiler/testData/diagnostics/testsWithStdLib/when/kt10192.kt index 8e8e9e94a07..ce3424bd489 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/when/kt10192.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/when/kt10192.kt @@ -1,4 +1,5 @@ // FIR_IDENTICAL +// LANGUAGE: +WarnAboutNonExhaustiveWhenOnAlgebraicTypes fun test1() { if (true) { when (true) { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java index d202308f762..b2eb6a2037c 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java @@ -31777,6 +31777,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/when/NonExhaustiveWarningNull.kt"); } + @Test + @TestMetadata("nonExhaustiveWhenStatement_1_5.kt") + public void testNonExhaustiveWhenStatement_1_5() throws Exception { + runTest("compiler/testData/diagnostics/tests/when/nonExhaustiveWhenStatement_1_5.kt"); + } + @Test @TestMetadata("nonExhaustiveWhenStatement_1_6.kt") public void testNonExhaustiveWhenStatement_1_6() throws Exception { diff --git a/compiler/tests-spec/testData/diagnostics/linked/expressions/when-expression/p-2/pos/1.1.kt b/compiler/tests-spec/testData/diagnostics/linked/expressions/when-expression/p-2/pos/1.1.kt index dcc80b91f6a..fb1914ed7a2 100644 --- a/compiler/tests-spec/testData/diagnostics/linked/expressions/when-expression/p-2/pos/1.1.kt +++ b/compiler/tests-spec/testData/diagnostics/linked/expressions/when-expression/p-2/pos/1.1.kt @@ -1,3 +1,4 @@ +// LANGUAGE: +WarnAboutNonExhaustiveWhenOnAlgebraicTypes // !DIAGNOSTICS: -UNUSED_EXPRESSION -DEBUG_INFO_SMARTCAST // SKIP_TXT diff --git a/compiler/tests-spec/testData/diagnostics/linked/expressions/when-expression/p-5/pos/1.1.kt b/compiler/tests-spec/testData/diagnostics/linked/expressions/when-expression/p-5/pos/1.1.kt index ecc3b820d94..90a6ee5215d 100644 --- a/compiler/tests-spec/testData/diagnostics/linked/expressions/when-expression/p-5/pos/1.1.kt +++ b/compiler/tests-spec/testData/diagnostics/linked/expressions/when-expression/p-5/pos/1.1.kt @@ -1,3 +1,4 @@ +// LANGUAGE: +WarnAboutNonExhaustiveWhenOnAlgebraicTypes // !DIAGNOSTICS: -UNUSED_EXPRESSION // SKIP_TXT diff --git a/compiler/tests-spec/testData/diagnostics/linked/expressions/when-expression/p-6/pos/1.2.kt b/compiler/tests-spec/testData/diagnostics/linked/expressions/when-expression/p-6/pos/1.2.kt index 5d742231c96..7fab328e73b 100644 --- a/compiler/tests-spec/testData/diagnostics/linked/expressions/when-expression/p-6/pos/1.2.kt +++ b/compiler/tests-spec/testData/diagnostics/linked/expressions/when-expression/p-6/pos/1.2.kt @@ -1,3 +1,4 @@ +// LANGUAGE: +WarnAboutNonExhaustiveWhenOnAlgebraicTypes // SKIP_TXT /* diff --git a/compiler/tests-spec/testData/diagnostics/linked/expressions/when-expression/p-6/pos/5.1.kt b/compiler/tests-spec/testData/diagnostics/linked/expressions/when-expression/p-6/pos/5.1.kt index 0d205b1b461..8d69c842584 100644 --- a/compiler/tests-spec/testData/diagnostics/linked/expressions/when-expression/p-6/pos/5.1.kt +++ b/compiler/tests-spec/testData/diagnostics/linked/expressions/when-expression/p-6/pos/5.1.kt @@ -1,3 +1,4 @@ +// LANGUAGE: +WarnAboutNonExhaustiveWhenOnAlgebraicTypes // SKIP_TXT /* diff --git a/compiler/tests-spec/testData/diagnostics/linked/expressions/when-expression/p-6/pos/5.2.kt b/compiler/tests-spec/testData/diagnostics/linked/expressions/when-expression/p-6/pos/5.2.kt index 2be65d181ad..c93d330a0a6 100644 --- a/compiler/tests-spec/testData/diagnostics/linked/expressions/when-expression/p-6/pos/5.2.kt +++ b/compiler/tests-spec/testData/diagnostics/linked/expressions/when-expression/p-6/pos/5.2.kt @@ -1,3 +1,4 @@ +// LANGUAGE: +WarnAboutNonExhaustiveWhenOnAlgebraicTypes // SKIP_TXT /* diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/controlFlow/initialization/neg/3.kt b/compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/controlFlow/initialization/neg/3.kt index b26d4a81172..51663b3e3a1 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/controlFlow/initialization/neg/3.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/controlFlow/initialization/neg/3.kt @@ -1,4 +1,5 @@ // FIR_IDE_IGNORE +// LANGUAGE: +WarnAboutNonExhaustiveWhenOnAlgebraicTypes // !USE_EXPERIMENTAL: kotlin.contracts.ExperimentalContracts // SKIP_TXT diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/smartcasts/neg/8.kt b/compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/smartcasts/neg/8.kt index c24c79bf9c0..961c5eb14f5 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/smartcasts/neg/8.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/smartcasts/neg/8.kt @@ -1,3 +1,4 @@ +// LANGUAGE: +WarnAboutNonExhaustiveWhenOnAlgebraicTypes // !USE_EXPERIMENTAL: kotlin.contracts.ExperimentalContracts /* diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/smartcasts/pos/8.kt b/compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/smartcasts/pos/8.kt index 9af0bb16713..b3073fff378 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/smartcasts/pos/8.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/smartcasts/pos/8.kt @@ -1,4 +1,5 @@ // FIR_IDE_IGNORE +// LANGUAGE: +WarnAboutNonExhaustiveWhenOnAlgebraicTypes // !USE_EXPERIMENTAL: kotlin.contracts.ExperimentalContracts /* diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/54.kt b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/54.kt index 677459a48ea..0475afbb4e7 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/54.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/54.kt @@ -1,4 +1,4 @@ -// !LANGUAGE: +NewInference +// LANGUAGE: +WarnAboutNonExhaustiveWhenOnAlgebraicTypes // !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE -UNUSED_VALUE -VARIABLE_WITH_REDUNDANT_INITIALIZER // SKIP_TXT diff --git a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt index 59e224d537c..6055452ecac 100644 --- a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt +++ b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt @@ -215,6 +215,7 @@ enum class LanguageFeature( ProhibitSimplificationOfNonTrivialConstBooleanExpressions(KOTLIN_1_6), TypeInferenceOnCallsWithSelfTypes(KOTLIN_1_6), OptInRelease(KOTLIN_1_6), + WarnAboutNonExhaustiveWhenOnAlgebraicTypes(KOTLIN_1_6, kind = BUG_FIX), // 1.7 diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java b/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java index 473c4a61085..acb31dd6845 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java @@ -31681,6 +31681,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag runTest("compiler/testData/diagnostics/tests/when/NonExhaustiveWarningNull.kt"); } + @Test + @TestMetadata("nonExhaustiveWhenStatement_1_5.kt") + public void testNonExhaustiveWhenStatement_1_5() throws Exception { + runTest("compiler/testData/diagnostics/tests/when/nonExhaustiveWhenStatement_1_5.kt"); + } + @Test @TestMetadata("nonExhaustiveWhenStatement_1_6.kt") public void testNonExhaustiveWhenStatement_1_6() throws Exception {