One non-processed branch is now allowed for if statement #KT-10805 Fixed
Also #EA-64033 Fixed
This commit is contained in:
committed by
Mikhail Glukhikh
parent
43b176de7e
commit
7e26fa6002
+41
-33
@@ -109,7 +109,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
if (elseBranch == null) {
|
if (elseBranch == null) {
|
||||||
if (thenBranch != null) {
|
if (thenBranch != null) {
|
||||||
KotlinTypeInfo result = getTypeInfoWhenOnlyOneBranchIsPresent(
|
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
|
// If jump was possible, take condition check info as the jump info
|
||||||
return result.getJumpOutPossible()
|
return result.getJumpOutPossible()
|
||||||
? result.replaceJumpOutPossible(true).replaceJumpFlowInfo(conditionDataFlowInfo)
|
? result.replaceJumpOutPossible(true).replaceJumpFlowInfo(conditionDataFlowInfo)
|
||||||
@@ -119,7 +119,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
}
|
}
|
||||||
if (thenBranch == null) {
|
if (thenBranch == null) {
|
||||||
return getTypeInfoWhenOnlyOneBranchIsPresent(
|
return getTypeInfoWhenOnlyOneBranchIsPresent(
|
||||||
elseBranch, elseScope, elseInfo, thenInfo, contextWithExpectedType, ifExpression, isStatement);
|
elseBranch, elseScope, elseInfo, thenInfo, contextWithExpectedType, ifExpression);
|
||||||
}
|
}
|
||||||
KtPsiFactory psiFactory = KtPsiFactoryKt.KtPsiFactory(ifExpression);
|
KtPsiFactory psiFactory = KtPsiFactoryKt.KtPsiFactory(ifExpression);
|
||||||
KtBlockExpression thenBlock = psiFactory.wrapInABlockWrapper(thenBranch);
|
KtBlockExpression thenBlock = psiFactory.wrapInABlockWrapper(thenBranch);
|
||||||
@@ -135,42 +135,51 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
BindingContext bindingContext = context.trace.getBindingContext();
|
BindingContext bindingContext = context.trace.getBindingContext();
|
||||||
KotlinTypeInfo thenTypeInfo = BindingContextUtils.getRecordedTypeInfo(thenBranch, bindingContext);
|
KotlinTypeInfo thenTypeInfo = BindingContextUtils.getRecordedTypeInfo(thenBranch, bindingContext);
|
||||||
KotlinTypeInfo elseTypeInfo = BindingContextUtils.getRecordedTypeInfo(elseBranch, bindingContext);
|
KotlinTypeInfo elseTypeInfo = BindingContextUtils.getRecordedTypeInfo(elseBranch, bindingContext);
|
||||||
assert thenTypeInfo != null : "'Then' branch of if expression was not processed: " + ifExpression;
|
assert thenTypeInfo != null || elseTypeInfo != null : "Both branches of if expression were not processed: " + ifExpression.getText();
|
||||||
assert elseTypeInfo != null : "'Else' branch of if expression was not processed: " + ifExpression;
|
|
||||||
|
|
||||||
KotlinType resultType = resolvedCall.getResultingDescriptor().getReturnType();
|
KotlinType resultType = resolvedCall.getResultingDescriptor().getReturnType();
|
||||||
KotlinType thenType = thenTypeInfo.getType();
|
boolean loopBreakContinuePossible = loopBreakContinuePossibleInCondition;
|
||||||
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);
|
|
||||||
|
|
||||||
DataFlowInfo resultDataFlowInfo;
|
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)) {
|
else if (thenTypeInfo == null) {
|
||||||
resultDataFlowInfo = elseDataFlowInfo;
|
loopBreakContinuePossible |= elseTypeInfo.getJumpOutPossible();
|
||||||
}
|
resultDataFlowInfo = elseTypeInfo.getDataFlowInfo();
|
||||||
else if (elseType == null || (jumpInElse && !jumpInThen)) {
|
|
||||||
resultDataFlowInfo = thenDataFlowInfo;
|
|
||||||
}
|
}
|
||||||
else {
|
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
|
// If break or continue was possible, take condition check info as the jump info
|
||||||
return TypeInfoFactoryKt.createTypeInfo(resultType, resultDataFlowInfo, loopBreakContinuePossible,
|
return TypeInfoFactoryKt.createTypeInfo(resultType, resultDataFlowInfo, loopBreakContinuePossible,
|
||||||
loopBreakContinuePossibleInCondition ? context.dataFlowInfo : conditionDataFlowInfo);
|
loopBreakContinuePossibleInCondition ? context.dataFlowInfo : conditionDataFlowInfo);
|
||||||
@@ -183,8 +192,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
@NotNull DataFlowInfo presentInfo,
|
@NotNull DataFlowInfo presentInfo,
|
||||||
@NotNull DataFlowInfo otherInfo,
|
@NotNull DataFlowInfo otherInfo,
|
||||||
@NotNull ExpressionTypingContext context,
|
@NotNull ExpressionTypingContext context,
|
||||||
@NotNull KtIfExpression ifExpression,
|
@NotNull KtIfExpression ifExpression
|
||||||
boolean isStatement
|
|
||||||
) {
|
) {
|
||||||
ExpressionTypingContext newContext = context.replaceDataFlowInfo(presentInfo).replaceExpectedType(NO_EXPECTED_TYPE)
|
ExpressionTypingContext newContext = context.replaceDataFlowInfo(presentInfo).replaceExpectedType(NO_EXPECTED_TYPE)
|
||||||
.replaceContextDependency(INDEPENDENT);
|
.replaceContextDependency(INDEPENDENT);
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
// AssertionError for nested ifs with lambdas and Nothing as results
|
||||||
|
|
||||||
|
val <!IMPLICIT_NOTHING_PROPERTY_TYPE!>fn<!> = if (true) {
|
||||||
|
<!TYPE_MISMATCH!>{ true }<!>
|
||||||
|
}
|
||||||
|
else if (true) {
|
||||||
|
<!TYPE_MISMATCH!>{ true }<!>
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
null!!
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public val fn: kotlin.Nothing
|
||||||
@@ -2877,6 +2877,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("kt1156.kt")
|
||||||
public void testKt1156() throws Exception {
|
public void testKt1156() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis/kt1156.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis/kt1156.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user