From 69927409fca27b35552bf32635d7cbb915c604aa Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Thu, 23 Jan 2020 15:02:36 +0300 Subject: [PATCH] [FIR] Fix exhaustiveness check when subject has flexible type --- .../FirWhenExhaustivenessTransformer.kt | 5 +++- .../exhaustiveWhenAndFlexibleType.kt | 19 ++++++++++-- .../exhaustiveWhenAndFlexibleType.txt | 29 +++++++++++++++---- .../fir/FirDiagnosticsTestGenerated.java | 10 +++---- ...DiagnosticsWithLightTreeTestGenerated.java | 10 +++---- 5 files changed, 54 insertions(+), 19 deletions(-) rename compiler/fir/resolve/testData/resolve/{problems => }/exhaustiveWhenAndFlexibleType.kt (51%) rename compiler/fir/resolve/testData/resolve/{problems => }/exhaustiveWhenAndFlexibleType.txt (58%) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirWhenExhaustivenessTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirWhenExhaustivenessTransformer.kt index efdadf6f96a..11b1824a14f 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirWhenExhaustivenessTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirWhenExhaustivenessTransformer.kt @@ -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) -> { diff --git a/compiler/fir/resolve/testData/resolve/problems/exhaustiveWhenAndFlexibleType.kt b/compiler/fir/resolve/testData/resolve/exhaustiveWhenAndFlexibleType.kt similarity index 51% rename from compiler/fir/resolve/testData/resolve/problems/exhaustiveWhenAndFlexibleType.kt rename to compiler/fir/resolve/testData/resolve/exhaustiveWhenAndFlexibleType.kt index 8b85624339c..c94f760b1e2 100644 --- a/compiler/fir/resolve/testData/resolve/problems/exhaustiveWhenAndFlexibleType.kt +++ b/compiler/fir/resolve/testData/resolve/exhaustiveWhenAndFlexibleType.kt @@ -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.length + s.length +} + +fun test_2() { + val e = Utils.getEnum() + val s = when (e) { + E.A -> "" + E.B -> "" + E.C -> "" + } + s.length } diff --git a/compiler/fir/resolve/testData/resolve/problems/exhaustiveWhenAndFlexibleType.txt b/compiler/fir/resolve/testData/resolve/exhaustiveWhenAndFlexibleType.txt similarity index 58% rename from compiler/fir/resolve/testData/resolve/problems/exhaustiveWhenAndFlexibleType.txt rename to compiler/fir/resolve/testData/resolve/exhaustiveWhenAndFlexibleType.txt index 27951a60548..748a3b7605e 100644 --- a/compiler/fir/resolve/testData/resolve/problems/exhaustiveWhenAndFlexibleType.txt +++ b/compiler/fir/resolve/testData/resolve/exhaustiveWhenAndFlexibleType.txt @@ -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!| = Q|Utils|.R|/Utils.getEnum|() - lval s: R|kotlin/Unit| = when (R|/e|) { - ==($subj$, Q|E|.R|/E.A|) || ==($subj$, Null(null)) -> { - ^test Unit + lval s: R|kotlin/String| = when (R|/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|/s|.# + R|/s|.R|kotlin/String.length| + } + public final fun test_2(): R|kotlin/Unit| { + lval e: R|ft!| = Q|Utils|.R|/Utils.getEnum|() + lval s: R|kotlin/String| = when (R|/e|) { + ==($subj$, Q|E|.R|/E.A|) -> { + String() + } + ==($subj$, Q|E|.R|/E.B|) -> { + String() + } + ==($subj$, Q|E|.R|/E.C|) -> { + String() + } + } + + R|/s|.R|kotlin/String.length| } diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java index 174122f52d1..310c3ad64e3 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java @@ -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"); diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java index cd21c577b1e..b4c39242d11 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java @@ -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");