From 6c7b32dc03a8a6837ed64e84352105d0f3da2adf Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Fri, 16 Nov 2012 15:42:14 +0400 Subject: [PATCH] Fix data flow info after inner loops with continue-outer ControlStructureTypingVisitor.containsBreak() is refined and now also takes into account continue to outer loops --- .../ControlStructureTypingVisitor.java | 34 ++++++++++++++----- .../ContinueOuterLoop.kt | 32 +++++++++++++++++ .../checkers/JetDiagnosticsTestGenerated.java | 5 +++ 3 files changed, 62 insertions(+), 9 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/dataFlowInfoTraversal/ContinueOuterLoop.kt diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ControlStructureTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ControlStructureTypingVisitor.java index b68cfbfe52f..8e146d272f9 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ControlStructureTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ControlStructureTypingVisitor.java @@ -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() { + loopExpression.accept(new JetTreeVisitor>() { @Override - public Void visitBreakExpression(JetBreakExpression breakExpression, JetLoopExpression outerLoop) { + public Void visitBreakExpression(JetBreakExpression breakExpression, List 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 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 outerLoops) { + List 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 { diff --git a/compiler/testData/diagnostics/tests/dataFlowInfoTraversal/ContinueOuterLoop.kt b/compiler/testData/diagnostics/tests/dataFlowInfoTraversal/ContinueOuterLoop.kt new file mode 100644 index 00000000000..5aec16dc745 --- /dev/null +++ b/compiler/testData/diagnostics/tests/dataFlowInfoTraversal/ContinueOuterLoop.kt @@ -0,0 +1,32 @@ +fun whileLoop(x: Int?) { + @outer while (x != 0) { + while (x != 1) { + if (x == 2) continue @outer + } + x : Int + } + x : Int +} + +fun doWhileLoop(x: Int?) { + @outer while (x != 0) { + do { + if (x == 2) continue @outer + } while (x == null) + x : Int + } + x : Int +} + +fun whileLoopContinueInnerOuter(x: Int?) { + @outer while (x != 0) { + @inner while (x != 1) { + while (x != 2) { + if (x == 3) continue @inner + } + x : Int + } + x : Int + } + x : Int +} diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index f8f53bfc714..a829e237c45 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -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");