[FIR] Report missing NO_ELSE_IN_WHEN for when statement with expect enums and sealed classes

^KT-59404 Fixed
This commit is contained in:
Ivan Kochurkin
2023-07-19 15:36:04 +02:00
committed by Space Team
parent 834bd1a71c
commit 8c39b2f71d
5 changed files with 18 additions and 15 deletions
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.diagnostics.WhenMissingCase import org.jetbrains.kotlin.diagnostics.WhenMissingCase
import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
import org.jetbrains.kotlin.fir.declarations.utils.modality import org.jetbrains.kotlin.fir.declarations.utils.modality
import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.impl.FirElseIfTrueCondition import org.jetbrains.kotlin.fir.expressions.impl.FirElseIfTrueCondition
@@ -120,19 +121,21 @@ class FirWhenExhaustivenessTransformer(private val bodyResolveComponents: BodyRe
return return
} }
val unwrappedIntersectionTypes = subjectType.unwrapIntersectionType()
var status: ExhaustivenessStatus = ExhaustivenessStatus.NotExhaustive.NO_ELSE_BRANCH var status: ExhaustivenessStatus = ExhaustivenessStatus.NotExhaustive.NO_ELSE_BRANCH
for (unwrappedSubjectType in unwrappedIntersectionTypes) { if (subjectType.toRegularClassSymbol(session)?.isExpect != true) {
val localStatus = computeStatusForNonIntersectionType(unwrappedSubjectType, session, whenExpression) val unwrappedIntersectionTypes = subjectType.unwrapIntersectionType()
when {
localStatus === ExhaustivenessStatus.ProperlyExhaustive -> { for (unwrappedSubjectType in unwrappedIntersectionTypes) {
status = localStatus val localStatus = computeStatusForNonIntersectionType(unwrappedSubjectType, session, whenExpression)
break when {
} localStatus === ExhaustivenessStatus.ProperlyExhaustive -> {
localStatus !== ExhaustivenessStatus.NotExhaustive.NO_ELSE_BRANCH && status === ExhaustivenessStatus.NotExhaustive.NO_ELSE_BRANCH -> { status = localStatus
status = localStatus break
}
localStatus !== ExhaustivenessStatus.NotExhaustive.NO_ELSE_BRANCH && status === ExhaustivenessStatus.NotExhaustive.NO_ELSE_BRANCH -> {
status = localStatus
}
} }
} }
} }
@@ -8,7 +8,7 @@ expect enum class Base {
} }
fun testCommon(base: Base) { fun testCommon(base: Base) {
val x = when (base) { // must be an error val x = <!NO_ELSE_IN_WHEN!>when<!> (base) { // must be an error
Base.A -> 1 Base.A -> 1
Base.B -> 2 Base.B -> 2
} }
@@ -9,7 +9,7 @@ class A : Base()
object B : Base() object B : Base()
fun testCommon(base: Base) { fun testCommon(base: Base) {
val x = when (base) { // must be an error val x = <!NO_ELSE_IN_WHEN!>when<!> (base) { // must be an error
is A -> 1 is A -> 1
B -> 2 B -> 2
} }
@@ -9,7 +9,7 @@ class A : Base
object B : Base object B : Base
fun testCommon(base: Base) { fun testCommon(base: Base) {
val x = when (base) { // must be an error val x = <!NO_ELSE_IN_WHEN!>when<!> (base) { // must be an error
is A -> 1 is A -> 1
B -> 2 B -> 2
} }
@@ -8,7 +8,7 @@ expect sealed class SealedClass() {
} }
fun whenForExpectSealed(s: SealedClass): Int { fun whenForExpectSealed(s: SealedClass): Int {
return when (s) { // should be error, because actual sealed class may add more implementations return <!NO_ELSE_IN_WHEN!>when<!> (s) { // should be error, because actual sealed class may add more implementations
is SealedClass.Nested.NestedDeeper -> 7 is SealedClass.Nested.NestedDeeper -> 7
is SealedClass.Nested -> 8 is SealedClass.Nested -> 8
} }