[FIR] Fix exhaustiveness check when subject has flexible type
This commit is contained in:
+4
-1
@@ -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.ConeLookupTagBasedType
|
||||||
import org.jetbrains.kotlin.fir.types.ConeNullability
|
import org.jetbrains.kotlin.fir.types.ConeNullability
|
||||||
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
|
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
|
||||||
|
import org.jetbrains.kotlin.fir.types.lowerBoundIfFlexible
|
||||||
import org.jetbrains.kotlin.fir.visitors.*
|
import org.jetbrains.kotlin.fir.visitors.*
|
||||||
import org.jetbrains.kotlin.name.ClassId
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
|
|
||||||
@@ -46,7 +47,9 @@ class FirWhenExhaustivenessTransformer(private val bodyResolveComponents: BodyRe
|
|||||||
?: (whenExpression.subject as? FirQualifiedAccessExpression)?.typeRef) as? FirResolvedTypeRef
|
?: (whenExpression.subject as? FirQualifiedAccessExpression)?.typeRef) as? FirResolvedTypeRef
|
||||||
?: return null
|
?: 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 nullable = typeRef.type.nullability == ConeNullability.NULLABLE
|
||||||
val isExhaustive = when {
|
val isExhaustive = when {
|
||||||
((lookupTag as? ConeClassLikeLookupTag)?.classId == bodyResolveComponents.session.builtinTypes.booleanType.id) -> {
|
((lookupTag as? ConeClassLikeLookupTag)?.classId == bodyResolveComponents.session.builtinTypes.booleanType.id) -> {
|
||||||
|
|||||||
+16
-3
@@ -1,3 +1,5 @@
|
|||||||
|
// IGNORE_LIGHT_TREE
|
||||||
|
|
||||||
// FILE: Utils.java
|
// FILE: Utils.java
|
||||||
|
|
||||||
public class Utils {
|
public class Utils {
|
||||||
@@ -12,12 +14,23 @@ enum class E {
|
|||||||
A, B, C
|
A, B, C
|
||||||
}
|
}
|
||||||
|
|
||||||
fun test() {
|
fun test_1() {
|
||||||
val e = Utils.getEnum()
|
val e = Utils.getEnum()
|
||||||
val s = when (e) {
|
val s = when (e) {
|
||||||
E.A, null -> return
|
null -> return
|
||||||
|
E.A -> ""
|
||||||
E.B -> ""
|
E.B -> ""
|
||||||
E.C -> ""
|
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
|
||||||
}
|
}
|
||||||
+24
-5
@@ -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 e: R|ft<E, E?>!| = Q|Utils|.R|/Utils.getEnum|()
|
||||||
lval s: R|kotlin/Unit| = when (R|<local>/e|) {
|
lval s: R|kotlin/String| = when (R|<local>/e|) {
|
||||||
==($subj$, Q|E|.R|/E.A|) || ==($subj$, Null(null)) -> {
|
==($subj$, Null(null)) -> {
|
||||||
^test Unit
|
^test_1 Unit
|
||||||
|
}
|
||||||
|
==($subj$, Q|E|.R|/E.A|) -> {
|
||||||
|
String()
|
||||||
}
|
}
|
||||||
==($subj$, Q|E|.R|/E.B|) -> {
|
==($subj$, Q|E|.R|/E.B|) -> {
|
||||||
String()
|
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|
|
||||||
}
|
}
|
||||||
+5
-5
@@ -78,6 +78,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
|
|||||||
runTest("compiler/fir/resolve/testData/resolve/enumWithCompanion.kt");
|
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")
|
@TestMetadata("exhaustiveness_boolean.kt")
|
||||||
public void testExhaustiveness_boolean() throws Exception {
|
public void testExhaustiveness_boolean() throws Exception {
|
||||||
runTest("compiler/fir/resolve/testData/resolve/exhaustiveness_boolean.kt");
|
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");
|
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")
|
@TestMetadata("incorrectSuperCall.kt")
|
||||||
public void testIncorrectSuperCall() throws Exception {
|
public void testIncorrectSuperCall() throws Exception {
|
||||||
runTest("compiler/fir/resolve/testData/resolve/problems/incorrectSuperCall.kt");
|
runTest("compiler/fir/resolve/testData/resolve/problems/incorrectSuperCall.kt");
|
||||||
|
|||||||
Generated
+5
-5
@@ -78,6 +78,11 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
|
|||||||
runTest("compiler/fir/resolve/testData/resolve/enumWithCompanion.kt");
|
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")
|
@TestMetadata("exhaustiveness_boolean.kt")
|
||||||
public void testExhaustiveness_boolean() throws Exception {
|
public void testExhaustiveness_boolean() throws Exception {
|
||||||
runTest("compiler/fir/resolve/testData/resolve/exhaustiveness_boolean.kt");
|
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");
|
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")
|
@TestMetadata("incorrectSuperCall.kt")
|
||||||
public void testIncorrectSuperCall() throws Exception {
|
public void testIncorrectSuperCall() throws Exception {
|
||||||
runTest("compiler/fir/resolve/testData/resolve/problems/incorrectSuperCall.kt");
|
runTest("compiler/fir/resolve/testData/resolve/problems/incorrectSuperCall.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user