K2: Resolve non-exhaustive when expressions independently
^KT-55169 Fixed ^KT-55175 Related
This commit is contained in:
committed by
Space Team
parent
9fa0f51a61
commit
04d3996e68
+6
@@ -35152,6 +35152,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
|
|||||||
runTest("compiler/testData/diagnostics/tests/when/NonExhaustiveBooleanNullable.kt");
|
runTest("compiler/testData/diagnostics/tests/when/NonExhaustiveBooleanNullable.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("nonExhaustiveDependentContext.kt")
|
||||||
|
public void testNonExhaustiveDependentContext() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/when/nonExhaustiveDependentContext.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("NonExhaustivePlatformEnum.kt")
|
@TestMetadata("NonExhaustivePlatformEnum.kt")
|
||||||
public void testNonExhaustivePlatformEnum() throws Exception {
|
public void testNonExhaustivePlatformEnum() throws Exception {
|
||||||
|
|||||||
+6
@@ -35248,6 +35248,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
|||||||
runTest("compiler/testData/diagnostics/tests/when/NonExhaustiveBooleanNullable.kt");
|
runTest("compiler/testData/diagnostics/tests/when/NonExhaustiveBooleanNullable.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("nonExhaustiveDependentContext.kt")
|
||||||
|
public void testNonExhaustiveDependentContext() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/when/nonExhaustiveDependentContext.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("NonExhaustivePlatformEnum.kt")
|
@TestMetadata("NonExhaustivePlatformEnum.kt")
|
||||||
public void testNonExhaustivePlatformEnum() throws Exception {
|
public void testNonExhaustivePlatformEnum() throws Exception {
|
||||||
|
|||||||
+6
@@ -35152,6 +35152,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
|||||||
runTest("compiler/testData/diagnostics/tests/when/NonExhaustiveBooleanNullable.kt");
|
runTest("compiler/testData/diagnostics/tests/when/NonExhaustiveBooleanNullable.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("nonExhaustiveDependentContext.kt")
|
||||||
|
public void testNonExhaustiveDependentContext() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/when/nonExhaustiveDependentContext.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("NonExhaustivePlatformEnum.kt")
|
@TestMetadata("NonExhaustivePlatformEnum.kt")
|
||||||
public void testNonExhaustivePlatformEnum() throws Exception {
|
public void testNonExhaustivePlatformEnum() throws Exception {
|
||||||
|
|||||||
+3
@@ -91,6 +91,9 @@ class FirWhenExhaustivenessTransformer(private val bodyResolveComponents: BodyRe
|
|||||||
throw IllegalArgumentException("Should not be there")
|
throw IllegalArgumentException("Should not be there")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The synthetic call for the whole [whenExpression] might be not completed yet
|
||||||
|
*/
|
||||||
override fun transformWhenExpression(whenExpression: FirWhenExpression, data: Any?): FirStatement {
|
override fun transformWhenExpression(whenExpression: FirWhenExpression, data: Any?): FirStatement {
|
||||||
processExhaustivenessCheck(whenExpression)
|
processExhaustivenessCheck(whenExpression)
|
||||||
bodyResolveComponents.session.enumWhenTracker?.reportEnumUsageInWhen(
|
bodyResolveComponents.session.enumWhenTracker?.reportEnumUsageInWhen(
|
||||||
|
|||||||
+25
-5
@@ -64,7 +64,7 @@ class FirControlFlowStatementsResolveTransformer(transformer: FirAbstractBodyRes
|
|||||||
@Suppress("NAME_SHADOWING")
|
@Suppress("NAME_SHADOWING")
|
||||||
var whenExpression = whenExpression.transformSubject(transformer, ResolutionMode.ContextIndependent)
|
var whenExpression = whenExpression.transformSubject(transformer, ResolutionMode.ContextIndependent)
|
||||||
val subjectType = whenExpression.subject?.typeRef?.coneType?.fullyExpandedType(session)
|
val subjectType = whenExpression.subject?.typeRef?.coneType?.fullyExpandedType(session)
|
||||||
var callCompleted = false
|
var completionNeeded = false
|
||||||
context.withWhenSubjectType(subjectType, components) {
|
context.withWhenSubjectType(subjectType, components) {
|
||||||
when {
|
when {
|
||||||
whenExpression.branches.isEmpty() -> {}
|
whenExpression.branches.isEmpty() -> {}
|
||||||
@@ -78,19 +78,39 @@ class FirControlFlowStatementsResolveTransformer(transformer: FirAbstractBodyRes
|
|||||||
|
|
||||||
whenExpression = syntheticCallGenerator.generateCalleeForWhenExpression(whenExpression, resolutionContext) ?: run {
|
whenExpression = syntheticCallGenerator.generateCalleeForWhenExpression(whenExpression, resolutionContext) ?: run {
|
||||||
whenExpression = whenExpression.transformSingle(whenExhaustivenessTransformer, null)
|
whenExpression = whenExpression.transformSingle(whenExhaustivenessTransformer, null)
|
||||||
dataFlowAnalyzer.exitWhenExpression(whenExpression, callCompleted)
|
dataFlowAnalyzer.exitWhenExpression(whenExpression, callCompleted = false)
|
||||||
whenExpression.resultType = buildErrorTypeRef {
|
whenExpression.resultType = buildErrorTypeRef {
|
||||||
diagnostic = ConeSimpleDiagnostic("Can't resolve when expression", DiagnosticKind.InferenceError)
|
diagnostic = ConeSimpleDiagnostic("Can't resolve when expression", DiagnosticKind.InferenceError)
|
||||||
}
|
}
|
||||||
return@withWhenSubjectType whenExpression
|
return@withWhenSubjectType whenExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
val completionResult = callCompleter.completeCall(whenExpression, data)
|
completionNeeded = true
|
||||||
whenExpression = completionResult.result
|
|
||||||
callCompleted = completionResult.callCompleted
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
whenExpression = whenExpression.transformSingle(whenExhaustivenessTransformer, null)
|
whenExpression = whenExpression.transformSingle(whenExhaustivenessTransformer, null)
|
||||||
|
|
||||||
|
// This is necessary to perform outside the place where the synthetic call is created because
|
||||||
|
// exhaustiveness is not yet computed there, but at the same time to compute it properly
|
||||||
|
// we need having branches condition bes analyzed that is why we can't have call
|
||||||
|
// `whenExpression.transformSingle(whenExhaustivenessTransformer, null)` at the beginning
|
||||||
|
val callCompleted = when {
|
||||||
|
completionNeeded -> {
|
||||||
|
val completionResult = callCompleter.completeCall(
|
||||||
|
whenExpression,
|
||||||
|
// For non-exhaustive when expressions, we should complete then as independent because below
|
||||||
|
// their type is artificially replaced with Unit, while candidate symbol's return type remains the same
|
||||||
|
// So when combining two when's the inner one was erroneously resolved as a normal dependent exhaustive sub-expression
|
||||||
|
// At the same time, it all looks suspicious and inconsistent, so we hope it would be investigated at KT-55175
|
||||||
|
if (whenExpression.isProperlyExhaustive) data else ResolutionMode.ContextIndependent,
|
||||||
|
)
|
||||||
|
whenExpression = completionResult.result
|
||||||
|
|
||||||
|
completionResult.callCompleted
|
||||||
|
}
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
|
||||||
dataFlowAnalyzer.exitWhenExpression(whenExpression, callCompleted)
|
dataFlowAnalyzer.exitWhenExpression(whenExpression, callCompleted)
|
||||||
whenExpression = whenExpression.replaceReturnTypeIfNotExhaustive()
|
whenExpression = whenExpression.replaceReturnTypeIfNotExhaustive()
|
||||||
whenExpression
|
whenExpression
|
||||||
|
|||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
// SKIP_TXT
|
||||||
|
fun bar(a: String): String {
|
||||||
|
return <!RETURN_TYPE_MISMATCH!>when {
|
||||||
|
a.length == 1 -> {
|
||||||
|
when { // Error in K1, no error in K2
|
||||||
|
a == "a" -> ""
|
||||||
|
a == "b" -> ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> ""
|
||||||
|
}<!>
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
// SKIP_TXT
|
||||||
|
fun bar(a: String): String {
|
||||||
|
return when {
|
||||||
|
a.length == 1 -> {
|
||||||
|
<!NO_ELSE_IN_WHEN!>when<!> { // Error in K1, no error in K2
|
||||||
|
a == "a" -> ""
|
||||||
|
a == "b" -> ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> ""
|
||||||
|
}
|
||||||
|
}
|
||||||
Generated
+6
@@ -35248,6 +35248,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
|||||||
runTest("compiler/testData/diagnostics/tests/when/NonExhaustiveBooleanNullable.kt");
|
runTest("compiler/testData/diagnostics/tests/when/NonExhaustiveBooleanNullable.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("nonExhaustiveDependentContext.kt")
|
||||||
|
public void testNonExhaustiveDependentContext() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/when/nonExhaustiveDependentContext.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("NonExhaustivePlatformEnum.kt")
|
@TestMetadata("NonExhaustivePlatformEnum.kt")
|
||||||
public void testNonExhaustivePlatformEnum() throws Exception {
|
public void testNonExhaustivePlatformEnum() throws Exception {
|
||||||
|
|||||||
Reference in New Issue
Block a user