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 387c875b7b2..024d351daea 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 @@ -17989,6 +17989,34 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti } } + @Nested + @TestMetadata("compiler/testData/diagnostics/tests/multiplatform/exhaustiveness") + @TestDataPath("$PROJECT_ROOT") + public class Exhaustiveness { + @Test + public void testAllFilesPresentInExhaustiveness() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/multiplatform/exhaustiveness"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); + } + + @Test + @TestMetadata("expectEnum.kt") + public void testExpectEnum() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/exhaustiveness/expectEnum.kt"); + } + + @Test + @TestMetadata("expectSealedClass.kt") + public void testExpectSealedClass() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/exhaustiveness/expectSealedClass.kt"); + } + + @Test + @TestMetadata("expectSealedInterface.kt") + public void testExpectSealedInterface() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/exhaustiveness/expectSealedInterface.kt"); + } + } + @Nested @TestMetadata("compiler/testData/diagnostics/tests/multiplatform/generic") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java index 532580a9a9d..bdfe5926fd4 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java @@ -24594,6 +24594,34 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT } } + @Nested + @TestMetadata("compiler/testData/codegen/box/multiplatform/exhaustiveness") + @TestDataPath("$PROJECT_ROOT") + public class Exhaustiveness { + @Test + public void testAllFilesPresentInExhaustiveness() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/multiplatform/exhaustiveness"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); + } + + @Test + @TestMetadata("commonEnum.kt") + public void testCommonEnum() throws Exception { + runTest("compiler/testData/codegen/box/multiplatform/exhaustiveness/commonEnum.kt"); + } + + @Test + @TestMetadata("commonSealedClass.kt") + public void testCommonSealedClass() throws Exception { + runTest("compiler/testData/codegen/box/multiplatform/exhaustiveness/commonSealedClass.kt"); + } + + @Test + @TestMetadata("commonSealedInterface.kt") + public void testCommonSealedInterface() throws Exception { + runTest("compiler/testData/codegen/box/multiplatform/exhaustiveness/commonSealedInterface.kt"); + } + } + @Nested @TestMetadata("compiler/testData/codegen/box/multiplatform/multiModule") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/frontend.common/src/org/jetbrains/kotlin/diagnostics/WhenMissingCase.kt b/compiler/frontend.common/src/org/jetbrains/kotlin/diagnostics/WhenMissingCase.kt index ffa9ef58e67..93bd7685288 100644 --- a/compiler/frontend.common/src/org/jetbrains/kotlin/diagnostics/WhenMissingCase.kt +++ b/compiler/frontend.common/src/org/jetbrains/kotlin/diagnostics/WhenMissingCase.kt @@ -17,6 +17,16 @@ sealed class WhenMissingCase { override val branchConditionText: String = "else" } + sealed class ConditionTypeIsExpect(val typeOfDeclaration: String) : WhenMissingCase() { + object SealedClass : ConditionTypeIsExpect("sealed class") + object SealedInterface : ConditionTypeIsExpect("sealed interface") + object Enum : ConditionTypeIsExpect("enum") + + override val branchConditionText: String = "else" + + override fun toString(): String = "unknown" + } + object NullIsMissing : WhenMissingCase() { override val branchConditionText: String = "null" } @@ -51,4 +61,4 @@ sealed class WhenMissingCase { override fun toString(): String { return branchConditionText } -} \ No newline at end of file +} 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 277f14cde72..ae70fd37de5 100644 --- a/compiler/frontend/cfg/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProviderImpl.kt +++ b/compiler/frontend/cfg/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProviderImpl.kt @@ -31,6 +31,7 @@ import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.DiagnosticFactory import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.diagnostics.Errors.* +import org.jetbrains.kotlin.diagnostics.WhenMissingCase import org.jetbrains.kotlin.idea.MainFunctionDetector import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.* @@ -1003,6 +1004,10 @@ class ControlFlowInformationProviderImpl private constructor( if (usedAsExpression && missingCases.isNotEmpty()) { if (elseEntry != null) continue trace.report(NO_ELSE_IN_WHEN.on(element, missingCases)) + missingCases.firstOrNull { it is WhenMissingCase.ConditionTypeIsExpect }?.let { + require(it is WhenMissingCase.ConditionTypeIsExpect) + trace.report(EXPECT_TYPE_IN_WHEN_WITHOUT_ELSE.on(element, it.typeOfDeclaration)) + } } else if (subjectExpression != null) { val subjectType = trace.getType(subjectExpression) if (elseEntry != null) { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/WhenChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/cfg/WhenChecker.kt index 3c50d8fa77b..349a71d603f 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/WhenChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/WhenChecker.kt @@ -18,6 +18,7 @@ package org.jetbrains.kotlin.cfg import com.intellij.psi.PsiElement import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.cfg.WhenOnEnumExhaustivenessChecker.enumEntries import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.Modality @@ -40,11 +41,13 @@ import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluat import org.jetbrains.kotlin.resolve.descriptorUtil.classId import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeUtils +import org.jetbrains.kotlin.utils.addIfNotNull +import org.jetbrains.kotlin.utils.addToStdlib.runIf import java.util.* val List.hasUnknown: Boolean - get() = firstOrNull() == WhenMissingCase.Unknown + get() = any { it == WhenMissingCase.Unknown || it is WhenMissingCase.ConditionTypeIsExpect } private interface WhenExhaustivenessChecker { fun getMissingCases( @@ -57,6 +60,21 @@ private interface WhenExhaustivenessChecker { fun isApplicable(subjectType: KotlinType): Boolean = false } +// It's not a regular exhaustiveness checker, invoke it only inside other checkers +private object WhenOnExpectExhaustivenessChecker { + fun getMissingCase(subjectDescriptor: ClassDescriptor?): WhenMissingCase? { + return runIf(subjectDescriptor?.isExpect == true) { + when (subjectDescriptor!!.kind) { + ClassKind.CLASS -> WhenMissingCase.ConditionTypeIsExpect.SealedClass + ClassKind.INTERFACE -> WhenMissingCase.ConditionTypeIsExpect.SealedInterface + ClassKind.ENUM_CLASS -> WhenMissingCase.ConditionTypeIsExpect.Enum + else -> WhenMissingCase.Unknown + } + } + } +} + + // It's not a regular exhaustiveness checker, invoke it only inside other checkers private object WhenOnNullableExhaustivenessChecker /* : WhenExhaustivenessChecker*/ { fun getMissingCases(expression: KtWhenExpression, context: BindingContext, nullable: Boolean) = @@ -209,6 +227,7 @@ internal abstract class WhenOnClassExhaustivenessChecker : WhenExhaustivenessChe } private object WhenOnEnumExhaustivenessChecker : WhenOnClassExhaustivenessChecker() { + @OptIn(ExperimentalStdlibApi::class) override fun getMissingCases( expression: KtWhenExpression, context: BindingContext, @@ -216,8 +235,11 @@ private object WhenOnEnumExhaustivenessChecker : WhenOnClassExhaustivenessChecke nullable: Boolean ): List { assert(isEnumClass(subjectDescriptor)) { "isWhenOnEnumExhaustive should be called with an enum class descriptor" } - return getMissingClassCases(expression, subjectDescriptor!!.enumEntries, context) + - WhenOnNullableExhaustivenessChecker.getMissingCases(expression, context, nullable) + return buildList { + addAll(getMissingClassCases(expression, subjectDescriptor!!.enumEntries, context)) + addAll(WhenOnNullableExhaustivenessChecker.getMissingCases(expression, context, nullable)) + addIfNotNull(WhenOnExpectExhaustivenessChecker.getMissingCase(subjectDescriptor)) + } } override fun isApplicable(subjectType: KotlinType): Boolean { @@ -226,7 +248,7 @@ private object WhenOnEnumExhaustivenessChecker : WhenOnClassExhaustivenessChecke } internal object WhenOnSealedExhaustivenessChecker : WhenOnClassExhaustivenessChecker() { - + @OptIn(ExperimentalStdlibApi::class) override fun getMissingCases( expression: KtWhenExpression, context: BindingContext, @@ -238,8 +260,11 @@ internal object WhenOnSealedExhaustivenessChecker : WhenOnClassExhaustivenessChe } val allSubclasses = subjectDescriptor!!.deepSealedSubclasses - return getMissingClassCases(expression, allSubclasses.toSet(), context) + - WhenOnNullableExhaustivenessChecker.getMissingCases(expression, context, nullable) + return buildList { + addAll(getMissingClassCases(expression, allSubclasses.toSet(), context)) + addAll(WhenOnNullableExhaustivenessChecker.getMissingCases(expression, context, nullable)) + addIfNotNull(WhenOnExpectExhaustivenessChecker.getMissingCase(subjectDescriptor)) + } } override fun isApplicable(subjectType: KotlinType): Boolean { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index ccb5cbe69e2..ab7f83c82cc 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -1057,6 +1057,7 @@ public interface Errors { DiagnosticFactory1> NON_EXHAUSTIVE_WHEN = DiagnosticFactory1.create(WARNING, WHEN_EXPRESSION); DiagnosticFactory1> NON_EXHAUSTIVE_WHEN_ON_SEALED_CLASS = DiagnosticFactory1.create(INFO, WHEN_EXPRESSION); + DiagnosticFactory1 EXPECT_TYPE_IN_WHEN_WITHOUT_ELSE = DiagnosticFactory1.create(ERROR, WHEN_EXPRESSION); DiagnosticFactory0 COMMA_IN_WHEN_CONDITION_WITHOUT_ARGUMENT = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 DUPLICATE_LABEL_IN_WHEN = DiagnosticFactory0.create(WARNING); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index 94e0885959a..5afaa849291 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -610,6 +610,7 @@ public class DefaultErrorMessages { MAP.put(NO_ELSE_IN_WHEN, "''when'' expression must be exhaustive, add necessary {0}", RENDER_WHEN_MISSING_CASES); MAP.put(NON_EXHAUSTIVE_WHEN, "''when'' expression on enum is recommended to be exhaustive, add {0}", RENDER_WHEN_MISSING_CASES); MAP.put(NON_EXHAUSTIVE_WHEN_ON_SEALED_CLASS, "''when'' expression on sealed classes is recommended to be exhaustive, add {0}", RENDER_WHEN_MISSING_CASES); + MAP.put(EXPECT_TYPE_IN_WHEN_WITHOUT_ELSE, "'when' with expect {0} as subject can not be exhaustive without else branch", STRING); MAP.put(TYPE_MISMATCH_IN_RANGE, "Type mismatch: incompatible types of range and element checked in it"); MAP.put(CYCLIC_INHERITANCE_HIERARCHY, "There's a cycle in the inheritance hierarchy for this type"); diff --git a/compiler/testData/codegen/box/multiplatform/exhaustiveness/commonEnum.kt b/compiler/testData/codegen/box/multiplatform/exhaustiveness/commonEnum.kt new file mode 100644 index 00000000000..0f57160b8a4 --- /dev/null +++ b/compiler/testData/codegen/box/multiplatform/exhaustiveness/commonEnum.kt @@ -0,0 +1,29 @@ +// IGNORE_BACKEND_FIR: JVM_IR +// TARGET_BACKEND: JVM +// !LANGUAGE: +MultiPlatformProjects +// ISSUE: KT-20306 + +// MODULE: m1-common +// FILE: common.kt +enum class Base { + A, B +} + +fun testCommon(base: Base) { + val x = when (base) { // must be Ok + Base.A -> 1 + Base.B -> 2 + } +} + +// MODULE: m1-jvm(m1-common) +// FILE: main.kt + +fun testPlatform(base: Base) { + val x = when (base) { // must be OK + Base.A -> 1 + Base.B -> 2 + } +} + +fun box() = "OK" diff --git a/compiler/testData/codegen/box/multiplatform/exhaustiveness/commonSealedClass.kt b/compiler/testData/codegen/box/multiplatform/exhaustiveness/commonSealedClass.kt new file mode 100644 index 00000000000..15c0d5bd1d2 --- /dev/null +++ b/compiler/testData/codegen/box/multiplatform/exhaustiveness/commonSealedClass.kt @@ -0,0 +1,30 @@ +// IGNORE_BACKEND_FIR: JVM_IR +// TARGET_BACKEND: JVM +// !LANGUAGE: +MultiPlatformProjects +// ISSUE: KT-44474 + +// MODULE: m1-common +// FILE: common.kt +sealed class Base() + +class A : Base() +object B : Base() + +fun testCommon(base: Base) { + val x = when (base) { // must be Ok + is A -> 1 + B -> 2 + } +} + +// MODULE: m1-jvm(m1-common) +// FILE: main.kt + +fun testPlatform(base: Base) { + val x = when (base) { // must be OK + is A -> 1 + B -> 2 + } +} + +fun box() = "OK" diff --git a/compiler/testData/codegen/box/multiplatform/exhaustiveness/commonSealedInterface.kt b/compiler/testData/codegen/box/multiplatform/exhaustiveness/commonSealedInterface.kt new file mode 100644 index 00000000000..dc85d2b73e1 --- /dev/null +++ b/compiler/testData/codegen/box/multiplatform/exhaustiveness/commonSealedInterface.kt @@ -0,0 +1,30 @@ +// IGNORE_BACKEND_FIR: JVM_IR +// TARGET_BACKEND: JVM +// !LANGUAGE: +MultiPlatformProjects +// ISSUE: KT-44474 + +// MODULE: m1-common +// FILE: common.kt +sealed interface Base + +interface A : Base +object B : Base + +fun testCommon(base: Base) { + val x = when (base) { // must be Ok + is A -> 1 + B -> 2 + } +} + +// MODULE: m1-jvm(m1-common) +// FILE: main.kt + +fun testPlatform(base: Base) { + val x = when (base) { // must be OK + is A -> 1 + B -> 2 + } +} + +fun box() = "OK" diff --git a/compiler/testData/diagnostics/tests/multiplatform/exhaustiveness/expectEnum.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/exhaustiveness/expectEnum.fir.kt new file mode 100644 index 00000000000..e901305cf87 --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/exhaustiveness/expectEnum.fir.kt @@ -0,0 +1,37 @@ +// !LANGUAGE: +MultiPlatformProjects +// !DIAGNOSTICS: -UNUSED_VARIABLE +// ISSUE: KT-20306 + +// MODULE: m1-common +// FILE: common.kt +expect enum class Base { + A, B +} + +fun testCommon(base: Base) { + val x = when (base) { // must be an error + Base.A -> 1 + Base.B -> 2 + } +} + +// MODULE: m1-jvm(m1-common) +// FILE: Base.kt +actual enum class Base { + A, B, C +} + +fun testPlatformGood(base: Base) { + val x = when (base) { // must be OK + Base.A -> 1 + Base.B -> 2 + Base.C -> 3 + } +} + +fun testPlatformBad(base: Base) { + val x = when (base) { // must be an error + Base.A -> 1 + Base.B -> 2 + } +} diff --git a/compiler/testData/diagnostics/tests/multiplatform/exhaustiveness/expectEnum.kt b/compiler/testData/diagnostics/tests/multiplatform/exhaustiveness/expectEnum.kt new file mode 100644 index 00000000000..541d2ac5e1c --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/exhaustiveness/expectEnum.kt @@ -0,0 +1,37 @@ +// !LANGUAGE: +MultiPlatformProjects +// !DIAGNOSTICS: -UNUSED_VARIABLE +// ISSUE: KT-20306 + +// MODULE: m1-common +// FILE: common.kt +expect enum class Base { + A, B +} + +fun testCommon(base: Base) { + val x = when (base) { // must be an error + Base.A -> 1 + Base.B -> 2 + } +} + +// MODULE: m1-jvm(m1-common) +// FILE: Base.kt +actual enum class Base { + A, B, C +} + +fun testPlatformGood(base: Base) { + val x = when (base) { // must be OK + Base.A -> 1 + Base.B -> 2 + Base.C -> 3 + } +} + +fun testPlatformBad(base: Base) { + val x = when (base) { // must be an error + Base.A -> 1 + Base.B -> 2 + } +} diff --git a/compiler/testData/diagnostics/tests/multiplatform/exhaustiveness/expectEnum.txt b/compiler/testData/diagnostics/tests/multiplatform/exhaustiveness/expectEnum.txt new file mode 100644 index 00000000000..84846a71a9b --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/exhaustiveness/expectEnum.txt @@ -0,0 +1,52 @@ +// -- Module: -- +package + +public fun testCommon(/*0*/ base: Base): kotlin.Unit + +public final expect enum class Base : kotlin.Enum { + expect enum entry A + + expect enum entry B + + 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: Base): kotlin.Int + public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + 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): Base + public final /*synthesized*/ fun values(): kotlin.Array +} + +// -- Module: -- +package + +public fun testCommon(/*0*/ base: Base): kotlin.Unit +public fun testPlatformBad(/*0*/ base: Base): kotlin.Unit +public fun testPlatformGood(/*0*/ base: Base): kotlin.Unit + +public final actual enum class Base : kotlin.Enum { + enum entry A + + enum entry B + + enum entry C + + private constructor Base() + 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: Base): 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): Base + public final /*synthesized*/ fun values(): kotlin.Array +} diff --git a/compiler/testData/diagnostics/tests/multiplatform/exhaustiveness/expectSealedClass.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/exhaustiveness/expectSealedClass.fir.kt new file mode 100644 index 00000000000..b4b5b3e516b --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/exhaustiveness/expectSealedClass.fir.kt @@ -0,0 +1,40 @@ +// !LANGUAGE: +MultiPlatformProjects +// !DIAGNOSTICS: -UNUSED_VARIABLE +// ISSUE: KT-44474 + +// MODULE: m1-common +// FILE: common.kt +expect sealed class Base() + +class A : Base() +object B : Base() + +fun testCommon(base: Base) { + val x = when (base) { // must be an error + is A -> 1 + B -> 2 + } +} + +// MODULE: m1-jvm(m1-common) +// FILE: Base.kt +actual sealed class Base + +// FILE: C.kt + +class C : Base() + +fun testPlatformGood(base: Base) { + val x = when (base) { // must be OK + is A -> 1 + B -> 2 + is C -> 3 + } +} + +fun testPlatformBad(base: Base) { + val x = when (base) { // must be an error + is A -> 1 + B -> 2 + } +} diff --git a/compiler/testData/diagnostics/tests/multiplatform/exhaustiveness/expectSealedClass.kt b/compiler/testData/diagnostics/tests/multiplatform/exhaustiveness/expectSealedClass.kt new file mode 100644 index 00000000000..996c39a0f95 --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/exhaustiveness/expectSealedClass.kt @@ -0,0 +1,40 @@ +// !LANGUAGE: +MultiPlatformProjects +// !DIAGNOSTICS: -UNUSED_VARIABLE +// ISSUE: KT-44474 + +// MODULE: m1-common +// FILE: common.kt +expect sealed class Base() + +class A : Base() +object B : Base() + +fun testCommon(base: Base) { + val x = when (base) { // must be an error + is A -> 1 + B -> 2 + } +} + +// MODULE: m1-jvm(m1-common) +// FILE: Base.kt +actual sealed class Base + +// FILE: C.kt + +class C : Base() + +fun testPlatformGood(base: Base) { + val x = when (base) { // must be OK + is A -> 1 + B -> 2 + is C -> 3 + } +} + +fun testPlatformBad(base: Base) { + val x = when (base) { // must be an error + is A -> 1 + B -> 2 + } +} diff --git a/compiler/testData/diagnostics/tests/multiplatform/exhaustiveness/expectSealedClass.txt b/compiler/testData/diagnostics/tests/multiplatform/exhaustiveness/expectSealedClass.txt new file mode 100644 index 00000000000..a0a9788f695 --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/exhaustiveness/expectSealedClass.txt @@ -0,0 +1,60 @@ +// -- Module: -- +package + +public fun testCommon(/*0*/ base: Base): kotlin.Unit + +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 object B : Base { + private 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 expect 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 +} + +// -- Module: -- +package + +public fun testCommon(/*0*/ base: Base): kotlin.Unit +public fun testPlatformBad(/*0*/ base: Base): kotlin.Unit +public fun testPlatformGood(/*0*/ base: Base): kotlin.Unit + +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 object B : Base { + private 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 actual 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 C : Base { + public constructor C() + 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 +} diff --git a/compiler/testData/diagnostics/tests/multiplatform/exhaustiveness/expectSealedInterface.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/exhaustiveness/expectSealedInterface.fir.kt new file mode 100644 index 00000000000..d3f32ee568c --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/exhaustiveness/expectSealedInterface.fir.kt @@ -0,0 +1,40 @@ +// !LANGUAGE: +MultiPlatformProjects +// !DIAGNOSTICS: -UNUSED_VARIABLE +// ISSUE: KT-44474 + +// MODULE: m1-common +// FILE: common.kt +expect sealed interface Base + +class A : Base +object B : Base + +fun testCommon(base: Base) { + val x = when (base) { // must be an error + is A -> 1 + B -> 2 + } +} + +// MODULE: m1-jvm(m1-common) +// FILE: Base.kt +actual sealed interface Base + +// FILE: C.kt + +interface C : Base + +fun testPlatformGood(base: Base) { + val x = when (base) { // must be OK + is A -> 1 + B -> 2 + is C -> 3 + } +} + +fun testPlatformBad(base: Base) { + val x = when (base) { // must be an error + is A -> 1 + B -> 2 + } +} diff --git a/compiler/testData/diagnostics/tests/multiplatform/exhaustiveness/expectSealedInterface.kt b/compiler/testData/diagnostics/tests/multiplatform/exhaustiveness/expectSealedInterface.kt new file mode 100644 index 00000000000..a41c023a1ac --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/exhaustiveness/expectSealedInterface.kt @@ -0,0 +1,40 @@ +// !LANGUAGE: +MultiPlatformProjects +// !DIAGNOSTICS: -UNUSED_VARIABLE +// ISSUE: KT-44474 + +// MODULE: m1-common +// FILE: common.kt +expect sealed interface Base + +class A : Base +object B : Base + +fun testCommon(base: Base) { + val x = when (base) { // must be an error + is A -> 1 + B -> 2 + } +} + +// MODULE: m1-jvm(m1-common) +// FILE: Base.kt +actual sealed interface Base + +// FILE: C.kt + +interface C : Base + +fun testPlatformGood(base: Base) { + val x = when (base) { // must be OK + is A -> 1 + B -> 2 + is C -> 3 + } +} + +fun testPlatformBad(base: Base) { + val x = when (base) { // must be an error + is A -> 1 + B -> 2 + } +} diff --git a/compiler/testData/diagnostics/tests/multiplatform/exhaustiveness/expectSealedInterface.txt b/compiler/testData/diagnostics/tests/multiplatform/exhaustiveness/expectSealedInterface.txt new file mode 100644 index 00000000000..0bad73e7e5b --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/exhaustiveness/expectSealedInterface.txt @@ -0,0 +1,58 @@ +// -- Module: -- +package + +public fun testCommon(/*0*/ base: Base): kotlin.Unit + +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 object B : Base { + private 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 expect interface 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 +} + +// -- Module: -- +package + +public fun testCommon(/*0*/ base: Base): kotlin.Unit +public fun testPlatformBad(/*0*/ base: Base): kotlin.Unit +public fun testPlatformGood(/*0*/ base: Base): kotlin.Unit + +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 object B : Base { + private 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 actual interface 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 interface C : 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 +} + 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 3a7ba5e4092..97fa85e4f4a 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 @@ -17995,6 +17995,34 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { } } + @Nested + @TestMetadata("compiler/testData/diagnostics/tests/multiplatform/exhaustiveness") + @TestDataPath("$PROJECT_ROOT") + public class Exhaustiveness { + @Test + public void testAllFilesPresentInExhaustiveness() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/multiplatform/exhaustiveness"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); + } + + @Test + @TestMetadata("expectEnum.kt") + public void testExpectEnum() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/exhaustiveness/expectEnum.kt"); + } + + @Test + @TestMetadata("expectSealedClass.kt") + public void testExpectSealedClass() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/exhaustiveness/expectSealedClass.kt"); + } + + @Test + @TestMetadata("expectSealedInterface.kt") + public void testExpectSealedInterface() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/exhaustiveness/expectSealedInterface.kt"); + } + } + @Nested @TestMetadata("compiler/testData/diagnostics/tests/multiplatform/generic") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java index 88b81a7831c..23a14b138d6 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java @@ -24594,6 +24594,34 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { } } + @Nested + @TestMetadata("compiler/testData/codegen/box/multiplatform/exhaustiveness") + @TestDataPath("$PROJECT_ROOT") + public class Exhaustiveness { + @Test + public void testAllFilesPresentInExhaustiveness() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/multiplatform/exhaustiveness"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true); + } + + @Test + @TestMetadata("commonEnum.kt") + public void testCommonEnum() throws Exception { + runTest("compiler/testData/codegen/box/multiplatform/exhaustiveness/commonEnum.kt"); + } + + @Test + @TestMetadata("commonSealedClass.kt") + public void testCommonSealedClass() throws Exception { + runTest("compiler/testData/codegen/box/multiplatform/exhaustiveness/commonSealedClass.kt"); + } + + @Test + @TestMetadata("commonSealedInterface.kt") + public void testCommonSealedInterface() throws Exception { + runTest("compiler/testData/codegen/box/multiplatform/exhaustiveness/commonSealedInterface.kt"); + } + } + @Nested @TestMetadata("compiler/testData/codegen/box/multiplatform/multiModule") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index 4707c9fa24f..0f0bcfb4398 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -24594,6 +24594,34 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes } } + @Nested + @TestMetadata("compiler/testData/codegen/box/multiplatform/exhaustiveness") + @TestDataPath("$PROJECT_ROOT") + public class Exhaustiveness { + @Test + public void testAllFilesPresentInExhaustiveness() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/multiplatform/exhaustiveness"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); + } + + @Test + @TestMetadata("commonEnum.kt") + public void testCommonEnum() throws Exception { + runTest("compiler/testData/codegen/box/multiplatform/exhaustiveness/commonEnum.kt"); + } + + @Test + @TestMetadata("commonSealedClass.kt") + public void testCommonSealedClass() throws Exception { + runTest("compiler/testData/codegen/box/multiplatform/exhaustiveness/commonSealedClass.kt"); + } + + @Test + @TestMetadata("commonSealedInterface.kt") + public void testCommonSealedInterface() throws Exception { + runTest("compiler/testData/codegen/box/multiplatform/exhaustiveness/commonSealedInterface.kt"); + } + } + @Nested @TestMetadata("compiler/testData/codegen/box/multiplatform/multiModule") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 16d66a423a8..6421982f87a 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -20877,6 +20877,34 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes } } + @TestMetadata("compiler/testData/codegen/box/multiplatform/exhaustiveness") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Exhaustiveness extends AbstractLightAnalysisModeTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath); + } + + public void testAllFilesPresentInExhaustiveness() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/multiplatform/exhaustiveness"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true); + } + + @TestMetadata("commonEnum.kt") + public void testCommonEnum() throws Exception { + runTest("compiler/testData/codegen/box/multiplatform/exhaustiveness/commonEnum.kt"); + } + + @TestMetadata("commonSealedClass.kt") + public void testCommonSealedClass() throws Exception { + runTest("compiler/testData/codegen/box/multiplatform/exhaustiveness/commonSealedClass.kt"); + } + + @TestMetadata("commonSealedInterface.kt") + public void testCommonSealedInterface() throws Exception { + runTest("compiler/testData/codegen/box/multiplatform/exhaustiveness/commonSealedInterface.kt"); + } + } + @TestMetadata("compiler/testData/codegen/box/multiplatform/multiModule") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/AddWhenRemainingBranchesFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/AddWhenRemainingBranchesFix.kt index d88d7a23718..40c89afbf57 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/AddWhenRemainingBranchesFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/AddWhenRemainingBranchesFix.kt @@ -90,8 +90,10 @@ class AddWhenRemainingBranchesFix( (whenCloseBrace.prevSibling as? PsiWhiteSpace)?.replace(psiFactory.createNewLine()) for (case in missingCases) { val branchConditionText = when (case) { - WhenMissingCase.Unknown, WhenMissingCase.NullIsMissing, is WhenMissingCase.BooleanIsMissing -> - case.branchConditionText + WhenMissingCase.Unknown, + WhenMissingCase.NullIsMissing, + is WhenMissingCase.BooleanIsMissing, + is WhenMissingCase.ConditionTypeIsExpect -> case.branchConditionText is WhenMissingCase.IsTypeCheckIsMissing -> if (case.isSingleton) { "" @@ -126,4 +128,4 @@ class AddWhenRemainingBranchesFix( } } } -} \ No newline at end of file +} diff --git a/idea/testData/multiplatform/whenExhaustivenessForSealed/common/common.kt b/idea/testData/multiplatform/whenExhaustivenessForSealed/common/common.kt index 9914c58c433..f395e63f231 100644 --- a/idea/testData/multiplatform/whenExhaustivenessForSealed/common/common.kt +++ b/idea/testData/multiplatform/whenExhaustivenessForSealed/common/common.kt @@ -2,6 +2,6 @@ expect sealed class when (t) { is CommonImplTestClass -> 0 } diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java index 3a93afa47d2..8bf63504c47 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java @@ -16457,6 +16457,19 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes } } + @TestMetadata("compiler/testData/codegen/box/multiplatform/exhaustiveness") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Exhaustiveness extends AbstractIrJsCodegenBoxES6Test { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR_ES6, testDataFilePath); + } + + public void testAllFilesPresentInExhaustiveness() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/multiplatform/exhaustiveness"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR_ES6, true); + } + } + @TestMetadata("compiler/testData/codegen/box/multiplatform/multiModule") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java index 14741b08f12..27a771449dc 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java @@ -15942,6 +15942,19 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { } } + @TestMetadata("compiler/testData/codegen/box/multiplatform/exhaustiveness") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Exhaustiveness extends AbstractIrJsCodegenBoxTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath); + } + + public void testAllFilesPresentInExhaustiveness() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/multiplatform/exhaustiveness"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true); + } + } + @TestMetadata("compiler/testData/codegen/box/multiplatform/multiModule") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index 47c49b6608a..53d87e03aac 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -16007,6 +16007,19 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { } } + @TestMetadata("compiler/testData/codegen/box/multiplatform/exhaustiveness") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Exhaustiveness extends AbstractJsCodegenBoxTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS, testDataFilePath); + } + + public void testAllFilesPresentInExhaustiveness() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/multiplatform/exhaustiveness"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true); + } + } + @TestMetadata("compiler/testData/codegen/box/multiplatform/multiModule") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java index 50846c28fd8..26bb2afc7c1 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java @@ -9833,6 +9833,19 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest } } + @TestMetadata("compiler/testData/codegen/box/multiplatform/exhaustiveness") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Exhaustiveness extends AbstractIrCodegenBoxWasmTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest0(this::doTest, TargetBackend.WASM, testDataFilePath); + } + + public void testAllFilesPresentInExhaustiveness() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/multiplatform/exhaustiveness"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.WASM, true); + } + } + @TestMetadata("compiler/testData/codegen/box/multiplatform/multiModule") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)