[FIR] Fix exhaustiveness check when subject has flexible type

This commit is contained in:
Dmitriy Novozhilov
2020-01-23 15:02:36 +03:00
parent 0f049fd536
commit 69927409fc
5 changed files with 54 additions and 19 deletions
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
import org.jetbrains.kotlin.fir.types.ConeLookupTagBasedType
import org.jetbrains.kotlin.fir.types.ConeNullability
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
import org.jetbrains.kotlin.fir.types.lowerBoundIfFlexible
import org.jetbrains.kotlin.fir.visitors.*
import org.jetbrains.kotlin.name.ClassId
@@ -46,7 +47,9 @@ class FirWhenExhaustivenessTransformer(private val bodyResolveComponents: BodyRe
?: (whenExpression.subject as? FirQualifiedAccessExpression)?.typeRef) as? FirResolvedTypeRef
?: return null
val lookupTag = (typeRef.type as? ConeLookupTagBasedType)?.lookupTag ?: return null
// TODO: add some report logic about flexible type (see WHEN_ENUM_CAN_BE_NULL_IN_JAVA diagnostic in old frontend)
val type = typeRef.type.lowerBoundIfFlexible()
val lookupTag = (type as? ConeLookupTagBasedType)?.lookupTag ?: return null
val nullable = typeRef.type.nullability == ConeNullability.NULLABLE
val isExhaustive = when {
((lookupTag as? ConeClassLikeLookupTag)?.classId == bodyResolveComponents.session.builtinTypes.booleanType.id) -> {
@@ -1,3 +1,5 @@
// IGNORE_LIGHT_TREE
// FILE: Utils.java
public class Utils {
@@ -12,12 +14,23 @@ enum class E {
A, B, C
}
fun test() {
fun test_1() {
val e = Utils.getEnum()
val s = when (e) {
E.A, null -> return
null -> return
E.A -> ""
E.B -> ""
E.C -> ""
}
s.<!UNRESOLVED_REFERENCE!>length<!>
s.length
}
fun test_2() {
val e = Utils.getEnum()
val s = when (e) {
E.A -> ""
E.B -> ""
E.C -> ""
}
s.length
}
@@ -32,11 +32,14 @@ FILE: main.kt
}
}
public final fun test(): R|kotlin/Unit| {
public final fun test_1(): R|kotlin/Unit| {
lval e: R|ft<E, E?>!| = Q|Utils|.R|/Utils.getEnum|()
lval s: R|kotlin/Unit| = when (R|<local>/e|) {
==($subj$, Q|E|.R|/E.A|) || ==($subj$, Null(null)) -> {
^test Unit
lval s: R|kotlin/String| = when (R|<local>/e|) {
==($subj$, Null(null)) -> {
^test_1 Unit
}
==($subj$, Q|E|.R|/E.A|) -> {
String()
}
==($subj$, Q|E|.R|/E.B|) -> {
String()
@@ -46,5 +49,21 @@ FILE: main.kt
}
}
R|<local>/s|.<Unresolved name: length>#
R|<local>/s|.R|kotlin/String.length|
}
public final fun test_2(): R|kotlin/Unit| {
lval e: R|ft<E, E?>!| = Q|Utils|.R|/Utils.getEnum|()
lval s: R|kotlin/String| = when (R|<local>/e|) {
==($subj$, Q|E|.R|/E.A|) -> {
String()
}
==($subj$, Q|E|.R|/E.B|) -> {
String()
}
==($subj$, Q|E|.R|/E.C|) -> {
String()
}
}
R|<local>/s|.R|kotlin/String.length|
}
@@ -78,6 +78,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
runTest("compiler/fir/resolve/testData/resolve/enumWithCompanion.kt");
}
@TestMetadata("exhaustiveWhenAndFlexibleType.kt")
public void testExhaustiveWhenAndFlexibleType() throws Exception {
runTest("compiler/fir/resolve/testData/resolve/exhaustiveWhenAndFlexibleType.kt");
}
@TestMetadata("exhaustiveness_boolean.kt")
public void testExhaustiveness_boolean() throws Exception {
runTest("compiler/fir/resolve/testData/resolve/exhaustiveness_boolean.kt");
@@ -1036,11 +1041,6 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
runTest("compiler/fir/resolve/testData/resolve/problems/definitelyNotNullAmbiguity.kt");
}
@TestMetadata("exhaustiveWhenAndFlexibleType.kt")
public void testExhaustiveWhenAndFlexibleType() throws Exception {
runTest("compiler/fir/resolve/testData/resolve/problems/exhaustiveWhenAndFlexibleType.kt");
}
@TestMetadata("incorrectSuperCall.kt")
public void testIncorrectSuperCall() throws Exception {
runTest("compiler/fir/resolve/testData/resolve/problems/incorrectSuperCall.kt");
@@ -78,6 +78,11 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
runTest("compiler/fir/resolve/testData/resolve/enumWithCompanion.kt");
}
@TestMetadata("exhaustiveWhenAndFlexibleType.kt")
public void testExhaustiveWhenAndFlexibleType() throws Exception {
runTest("compiler/fir/resolve/testData/resolve/exhaustiveWhenAndFlexibleType.kt");
}
@TestMetadata("exhaustiveness_boolean.kt")
public void testExhaustiveness_boolean() throws Exception {
runTest("compiler/fir/resolve/testData/resolve/exhaustiveness_boolean.kt");
@@ -1036,11 +1041,6 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
runTest("compiler/fir/resolve/testData/resolve/problems/definitelyNotNullAmbiguity.kt");
}
@TestMetadata("exhaustiveWhenAndFlexibleType.kt")
public void testExhaustiveWhenAndFlexibleType() throws Exception {
runTest("compiler/fir/resolve/testData/resolve/problems/exhaustiveWhenAndFlexibleType.kt");
}
@TestMetadata("incorrectSuperCall.kt")
public void testIncorrectSuperCall() throws Exception {
runTest("compiler/fir/resolve/testData/resolve/problems/incorrectSuperCall.kt");