Fix data flow info after inner loops with continue-outer

ControlStructureTypingVisitor.containsBreak() is refined and now also takes
into account continue to outer loops
This commit is contained in:
Alexander Udalov
2012-11-16 15:42:14 +04:00
parent d1de446ae0
commit 6c7b32dc03
3 changed files with 62 additions and 9 deletions
@@ -16,6 +16,7 @@
package org.jetbrains.jet.lang.types.expressions;
import com.google.common.collect.Lists;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
@@ -171,32 +172,47 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
context.expressionTypingServices.getBlockReturnedTypeWithWritableScope(scopeToExtend, Collections.singletonList(body), CoercionStrategy.NO_COERCION, context.replaceDataFlowInfo(conditionInfo), context.trace);
}
if (!containsBreak(expression, context)) {
if (!containsJumpOutOfLoop(expression, context)) {
dataFlowInfo = DataFlowUtils.extractDataFlowInfoFromCondition(condition, false, context).and(dataFlowInfo);
}
return DataFlowUtils.checkType(KotlinBuiltIns.getInstance().getUnitType(), expression, contextWithExpectedType, dataFlowInfo);
}
private boolean containsBreak(final JetLoopExpression loopExpression, final ExpressionTypingContext context) {
private boolean containsJumpOutOfLoop(final JetLoopExpression loopExpression, final ExpressionTypingContext context) {
final boolean[] result = new boolean[1];
result[0] = false;
//todo breaks in inline function literals
loopExpression.accept(new JetTreeVisitor<JetLoopExpression>() {
loopExpression.accept(new JetTreeVisitor<List<JetLoopExpression>>() {
@Override
public Void visitBreakExpression(JetBreakExpression breakExpression, JetLoopExpression outerLoop) {
public Void visitBreakExpression(JetBreakExpression breakExpression, List<JetLoopExpression> outerLoops) {
JetSimpleNameExpression targetLabel = breakExpression.getTargetLabel();
PsiElement element = targetLabel != null ? context.trace.get(LABEL_TARGET, targetLabel) : null;
if (element == loopExpression || (targetLabel == null && outerLoop == loopExpression)) {
if (element == loopExpression || (targetLabel == null && outerLoops.get(outerLoops.size() - 1) == loopExpression)) {
result[0] = true;
}
return null;
}
@Override
public Void visitLoopExpression(JetLoopExpression loopExpression, JetLoopExpression outerLoop) {
return super.visitLoopExpression(loopExpression, loopExpression);
public Void visitContinueExpression(JetContinueExpression expression, List<JetLoopExpression> outerLoops) {
// continue@someOuterLoop is also considered as break
JetSimpleNameExpression targetLabel = expression.getTargetLabel();
if (targetLabel != null) {
PsiElement element = context.trace.get(LABEL_TARGET, targetLabel);
if (element instanceof JetLoopExpression && !outerLoops.contains(element)) {
result[0] = true;
}
}
return null;
}
}, loopExpression);
@Override
public Void visitLoopExpression(JetLoopExpression loopExpression, List<JetLoopExpression> outerLoops) {
List<JetLoopExpression> newOuterLoops = Lists.newArrayList(outerLoops);
newOuterLoops.add(loopExpression);
return super.visitLoopExpression(loopExpression, newOuterLoops);
}
}, Lists.newArrayList(loopExpression));
return result[0];
}
@@ -238,7 +254,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
JetExpression condition = expression.getCondition();
DataFlowInfo conditionDataFlowInfo = checkCondition(conditionScope, condition, context);
DataFlowInfo dataFlowInfo;
if (!containsBreak(expression, context)) {
if (!containsJumpOutOfLoop(expression, context)) {
dataFlowInfo = DataFlowUtils.extractDataFlowInfoFromCondition(condition, false, context).and(conditionDataFlowInfo);
}
else {
@@ -0,0 +1,32 @@
fun whileLoop(x: Int?) {
@outer while (x != 0) {
while (x != 1) {
if (x == 2) continue @outer
}
<!TYPE_MISMATCH!>x<!> : Int
}
x : Int
}
fun doWhileLoop(x: Int?) {
@outer while (x != 0) {
do {
if (x == 2) continue @outer
} while (x == null)
<!TYPE_MISMATCH!>x<!> : Int
}
x : Int
}
fun whileLoopContinueInnerOuter(x: Int?) {
@outer while (x != 0) {
@inner while (x != 1) {
while (x != 2) {
if (x == 3) continue @inner
}
<!TYPE_MISMATCH!>x<!> : Int
}
x : Int
}
x : Int
}
@@ -1221,6 +1221,11 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
doTest("compiler/testData/diagnostics/tests/dataFlowInfoTraversal/Condition.kt");
}
@TestMetadata("ContinueOuterLoop.kt")
public void testContinueOuterLoop() throws Exception {
doTest("compiler/testData/diagnostics/tests/dataFlowInfoTraversal/ContinueOuterLoop.kt");
}
@TestMetadata("DeepIf.kt")
public void testDeepIf() throws Exception {
doTest("compiler/testData/diagnostics/tests/dataFlowInfoTraversal/DeepIf.kt");