From 7e26fa600233605b96eb6e09a92f59df0e122f0c Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Wed, 27 Jan 2016 14:55:11 +0300 Subject: [PATCH] One non-processed branch is now allowed for if statement #KT-10805 Fixed Also #EA-64033 Fixed --- .../ControlStructureTypingVisitor.java | 74 ++++++++++--------- .../tests/controlFlowAnalysis/kt10805.kt | 11 +++ .../tests/controlFlowAnalysis/kt10805.txt | 3 + .../checkers/DiagnosticsTestGenerated.java | 6 ++ 4 files changed, 61 insertions(+), 33 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/controlFlowAnalysis/kt10805.kt create mode 100644 compiler/testData/diagnostics/tests/controlFlowAnalysis/kt10805.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingVisitor.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingVisitor.java index f1e582641c7..4726eebc6f0 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingVisitor.java @@ -109,7 +109,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { if (elseBranch == null) { if (thenBranch != null) { KotlinTypeInfo result = getTypeInfoWhenOnlyOneBranchIsPresent( - thenBranch, thenScope, thenInfo, elseInfo, contextWithExpectedType, ifExpression, isStatement); + thenBranch, thenScope, thenInfo, elseInfo, contextWithExpectedType, ifExpression); // If jump was possible, take condition check info as the jump info return result.getJumpOutPossible() ? result.replaceJumpOutPossible(true).replaceJumpFlowInfo(conditionDataFlowInfo) @@ -119,7 +119,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { } if (thenBranch == null) { return getTypeInfoWhenOnlyOneBranchIsPresent( - elseBranch, elseScope, elseInfo, thenInfo, contextWithExpectedType, ifExpression, isStatement); + elseBranch, elseScope, elseInfo, thenInfo, contextWithExpectedType, ifExpression); } KtPsiFactory psiFactory = KtPsiFactoryKt.KtPsiFactory(ifExpression); KtBlockExpression thenBlock = psiFactory.wrapInABlockWrapper(thenBranch); @@ -135,42 +135,51 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { BindingContext bindingContext = context.trace.getBindingContext(); KotlinTypeInfo thenTypeInfo = BindingContextUtils.getRecordedTypeInfo(thenBranch, bindingContext); KotlinTypeInfo elseTypeInfo = BindingContextUtils.getRecordedTypeInfo(elseBranch, bindingContext); - assert thenTypeInfo != null : "'Then' branch of if expression was not processed: " + ifExpression; - assert elseTypeInfo != null : "'Else' branch of if expression was not processed: " + ifExpression; + assert thenTypeInfo != null || elseTypeInfo != null : "Both branches of if expression were not processed: " + ifExpression.getText(); KotlinType resultType = resolvedCall.getResultingDescriptor().getReturnType(); - KotlinType thenType = thenTypeInfo.getType(); - KotlinType elseType = elseTypeInfo.getType(); - DataFlowInfo thenDataFlowInfo = thenTypeInfo.getDataFlowInfo(); - DataFlowInfo elseDataFlowInfo = elseTypeInfo.getDataFlowInfo(); - if (resultType != null && thenType != null && elseType != null) { - DataFlowValue resultValue = DataFlowValueFactory.createDataFlowValue(ifExpression, resultType, context); - DataFlowValue thenValue = DataFlowValueFactory.createDataFlowValue(thenBranch, thenType, context); - thenDataFlowInfo = thenDataFlowInfo.assign(resultValue, thenValue); - DataFlowValue elseValue = DataFlowValueFactory.createDataFlowValue(elseBranch, elseType, context); - elseDataFlowInfo = elseDataFlowInfo.assign(resultValue, elseValue); - } - - boolean loopBreakContinuePossible = loopBreakContinuePossibleInCondition || - thenTypeInfo.getJumpOutPossible() || elseTypeInfo.getJumpOutPossible(); - - boolean jumpInThen = thenType != null && KotlinBuiltIns.isNothing(thenType); - boolean jumpInElse = elseType != null && KotlinBuiltIns.isNothing(elseType); - + boolean loopBreakContinuePossible = loopBreakContinuePossibleInCondition; DataFlowInfo resultDataFlowInfo; - if (thenType == null && elseType == null) { - resultDataFlowInfo = thenDataFlowInfo.or(elseDataFlowInfo); + + if (elseTypeInfo == null) { + loopBreakContinuePossible |= thenTypeInfo.getJumpOutPossible(); + resultDataFlowInfo = thenTypeInfo.getDataFlowInfo(); } - else if (thenType == null || (jumpInThen && !jumpInElse)) { - resultDataFlowInfo = elseDataFlowInfo; - } - else if (elseType == null || (jumpInElse && !jumpInThen)) { - resultDataFlowInfo = thenDataFlowInfo; + else if (thenTypeInfo == null) { + loopBreakContinuePossible |= elseTypeInfo.getJumpOutPossible(); + resultDataFlowInfo = elseTypeInfo.getDataFlowInfo(); } else { - resultDataFlowInfo = thenDataFlowInfo.or(elseDataFlowInfo); - } + KotlinType thenType = thenTypeInfo.getType(); + KotlinType elseType = elseTypeInfo.getType(); + DataFlowInfo thenDataFlowInfo = thenTypeInfo.getDataFlowInfo(); + DataFlowInfo elseDataFlowInfo = elseTypeInfo.getDataFlowInfo(); + if (resultType != null && thenType != null && elseType != null) { + DataFlowValue resultValue = DataFlowValueFactory.createDataFlowValue(ifExpression, resultType, context); + DataFlowValue thenValue = DataFlowValueFactory.createDataFlowValue(thenBranch, thenType, context); + thenDataFlowInfo = thenDataFlowInfo.assign(resultValue, thenValue); + DataFlowValue elseValue = DataFlowValueFactory.createDataFlowValue(elseBranch, elseType, context); + elseDataFlowInfo = elseDataFlowInfo.assign(resultValue, elseValue); + } + loopBreakContinuePossible |= thenTypeInfo.getJumpOutPossible() || elseTypeInfo.getJumpOutPossible(); + + boolean jumpInThen = thenType != null && KotlinBuiltIns.isNothing(thenType); + boolean jumpInElse = elseType != null && KotlinBuiltIns.isNothing(elseType); + + if (thenType == null && elseType == null) { + resultDataFlowInfo = thenDataFlowInfo.or(elseDataFlowInfo); + } + else if (thenType == null || (jumpInThen && !jumpInElse)) { + resultDataFlowInfo = elseDataFlowInfo; + } + else if (elseType == null || (jumpInElse && !jumpInThen)) { + resultDataFlowInfo = thenDataFlowInfo; + } + else { + resultDataFlowInfo = thenDataFlowInfo.or(elseDataFlowInfo); + } + } // If break or continue was possible, take condition check info as the jump info return TypeInfoFactoryKt.createTypeInfo(resultType, resultDataFlowInfo, loopBreakContinuePossible, loopBreakContinuePossibleInCondition ? context.dataFlowInfo : conditionDataFlowInfo); @@ -183,8 +192,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { @NotNull DataFlowInfo presentInfo, @NotNull DataFlowInfo otherInfo, @NotNull ExpressionTypingContext context, - @NotNull KtIfExpression ifExpression, - boolean isStatement + @NotNull KtIfExpression ifExpression ) { ExpressionTypingContext newContext = context.replaceDataFlowInfo(presentInfo).replaceExpectedType(NO_EXPECTED_TYPE) .replaceContextDependency(INDEPENDENT); diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt10805.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt10805.kt new file mode 100644 index 00000000000..c5e39957b4d --- /dev/null +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt10805.kt @@ -0,0 +1,11 @@ +// AssertionError for nested ifs with lambdas and Nothing as results + +val fn = if (true) { + { true } +} +else if (true) { + { true } +} +else { + null!! +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt10805.txt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt10805.txt new file mode 100644 index 00000000000..cbb332edaab --- /dev/null +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt10805.txt @@ -0,0 +1,3 @@ +package + +public val fn: kotlin.Nothing diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index c9b7752d224..2d8be884fd8 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -2877,6 +2877,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("kt10805.kt") + public void testKt10805() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis/kt10805.kt"); + doTest(fileName); + } + @TestMetadata("kt1156.kt") public void testKt1156() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis/kt1156.kt");