diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java index f80a31ea08f..b228032054d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java @@ -30,9 +30,13 @@ import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContextUtils; import org.jetbrains.jet.lang.resolve.BindingTrace; +import org.jetbrains.jet.lang.resolve.constants.BooleanValue; +import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; +import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstantResolver; import org.jetbrains.jet.lang.types.lang.JetStandardClasses; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.expressions.OperatorConventions; +import org.jetbrains.jet.lang.types.lang.JetStandardLibrary; import org.jetbrains.jet.lexer.JetTokens; import java.util.Iterator; @@ -477,7 +481,15 @@ public class JetControlFlowProcessor { if (condition != null) { value(condition, true); } - builder.jumpOnFalse(loopInfo.getExitPoint()); + boolean conditionIsTrueConstant = false; + if (condition instanceof JetConstantExpression && condition.getNode().getElementType() == JetNodeTypes.BOOLEAN_CONSTANT) { + if (BooleanValue.TRUE == new CompileTimeConstantResolver().getBooleanValue(condition.getText(), JetStandardLibrary.getInstance().getBooleanType())) { + conditionIsTrueConstant = true; + } + } + if (!conditionIsTrueConstant) { + builder.jumpOnFalse(loopInfo.getExitPoint()); + } builder.bindLabel(loopInfo.getBodyEntryPoint()); JetExpression body = expression.getBody(); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/constants/CompileTimeConstantResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/constants/CompileTimeConstantResolver.java index 0fa2aa91a7d..91356a5927f 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/constants/CompileTimeConstantResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/constants/CompileTimeConstantResolver.java @@ -38,11 +38,9 @@ public class CompileTimeConstantResolver { public static final ErrorValue OUT_OF_RANGE = new ErrorValue("The value is out of range"); private final JetStandardLibrary standardLibrary; - private final BindingTrace trace; - public CompileTimeConstantResolver(@NotNull BindingTrace trace) { + public CompileTimeConstantResolver() { this.standardLibrary = JetStandardLibrary.getInstance(); - this.trace = trace; } @NotNull diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingContext.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingContext.java index fbeb2f64985..3067164efe4 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingContext.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingContext.java @@ -147,7 +147,7 @@ public class ExpressionTypingContext { public CompileTimeConstantResolver getCompileTimeConstantResolver() { if (compileTimeConstantResolver == null) { - compileTimeConstantResolver = new CompileTimeConstantResolver(trace); + compileTimeConstantResolver = new CompileTimeConstantResolver(); } return compileTimeConstantResolver; } diff --git a/compiler/testData/cfg/Finally.instructions b/compiler/testData/cfg/Finally.instructions index 470a05454b2..0f49c8ecfc4 100644 --- a/compiler/testData/cfg/Finally.instructions +++ b/compiler/testData/cfg/Finally.instructions @@ -301,7 +301,7 @@ fun t5() { } --------------------- l0: - NEXT:[r(while(true) { try { 1 if (..)] PREV:[] + NEXT:[r(while(true) { try { 1 if (..)] PREV:[] r(while(true) { try { 1 @@ -311,11 +311,10 @@ l0: } finally { 2 } - }) NEXT:[r(true)] PREV:[] + }) NEXT:[r(true)] PREV:[] l2: l5: - r(true) NEXT:[jf(l3)] PREV:[r(while(true) { try { 1 if (..), jmp(l2)] - jf(l3) NEXT:[read (Unit), r(try { 1 if (2 > 3) { break..)] PREV:[r(true)] + r(true) NEXT:[r(try { 1 if (2 > 3) { break..)] PREV:[r(while(true) { try { 1 if (..), jmp(l2)] l4: r(try { 1 @@ -324,31 +323,31 @@ l4: } } finally { 2 - }) NEXT:[r(1)] PREV:[jf(l3)] - r(1) NEXT:[r(2)] PREV:[r(try { 1 if (2 > 3) { break..)] - r(2) NEXT:[r(3)] PREV:[r(1)] - r(3) NEXT:[r(>)] PREV:[r(2)] - r(>) NEXT:[r(2 > 3)] PREV:[r(3)] - r(2 > 3) NEXT:[jf(l6)] PREV:[r(>)] - jf(l6) NEXT:[read (Unit), r(2)] PREV:[r(2 > 3)] - r(2) NEXT:[jmp(l3)] PREV:[jf(l6)] - jmp(l3) NEXT:[read (Unit)] PREV:[r(2)] -- jmp(l7) NEXT:[r(2)] PREV:[] + }) NEXT:[r(1)] PREV:[r(true)] + r(1) NEXT:[r(2)] PREV:[r(try { 1 if (2 > 3) { break..)] + r(2) NEXT:[r(3)] PREV:[r(1)] + r(3) NEXT:[r(>)] PREV:[r(2)] + r(>) NEXT:[r(2 > 3)] PREV:[r(3)] + r(2 > 3) NEXT:[jf(l6)] PREV:[r(>)] + jf(l6) NEXT:[read (Unit), r(2)] PREV:[r(2 > 3)] + r(2) NEXT:[jmp(l3)] PREV:[jf(l6)] + jmp(l3) NEXT:[read (Unit)] PREV:[r(2)] +- jmp(l7) NEXT:[r(2)] PREV:[] l6: - read (Unit) NEXT:[r(2)] PREV:[jf(l6)] + read (Unit) NEXT:[r(2)] PREV:[jf(l6)] l7: l8: - r(2) NEXT:[jmp(l2)] PREV:[read (Unit)] + r(2) NEXT:[jmp(l2)] PREV:[read (Unit)] l9: - jmp(l2) NEXT:[r(true)] PREV:[r(2)] + jmp(l2) NEXT:[r(true)] PREV:[r(2)] l3: - read (Unit) NEXT:[] PREV:[jf(l3), jmp(l3)] + read (Unit) NEXT:[] PREV:[jmp(l3)] l1: - NEXT:[] PREV:[read (Unit)] + NEXT:[] PREV:[read (Unit)] error: - NEXT:[] PREV:[] + NEXT:[] PREV:[] sink: - NEXT:[] PREV:[, ] + NEXT:[] PREV:[, ] ===================== == t6 == fun t6() { @@ -386,10 +385,9 @@ l0: }) NEXT:[r(true)] PREV:[r(try { @ while(true) { 1 if..)] l2: l5: - r(true) NEXT:[jf(l3)] PREV:[r(while(true) { 1 if (2 > 3)..), jmp(l2)] - jf(l3) NEXT:[read (Unit), r(1)] PREV:[r(true)] + r(true) NEXT:[r(1)] PREV:[r(while(true) { 1 if (2 > 3)..), jmp(l2)] l4: - r(1) NEXT:[r(2)] PREV:[jf(l3)] + r(1) NEXT:[r(2)] PREV:[r(true)] r(2) NEXT:[r(3)] PREV:[r(1)] r(3) NEXT:[r(>)] PREV:[r(2)] r(>) NEXT:[r(2 > 3)] PREV:[r(3)] @@ -402,7 +400,7 @@ l6: l7: jmp(l2) NEXT:[r(true)] PREV:[read (Unit)] l3: - read (Unit) NEXT:[r(5)] PREV:[jf(l3), jmp(l3)] + read (Unit) NEXT:[r(5)] PREV:[jmp(l3)] r(5) NEXT:[r(2)] PREV:[read (Unit)] l8: r(2) NEXT:[] PREV:[r(5)] @@ -448,10 +446,9 @@ l0: }) NEXT:[r(true)] PREV:[r(try { @ while(true) { 1 if..)] l2: l5: - r(true) NEXT:[jf(l3)] PREV:[r(while(true) { 1 if (2 > 3)..), jmp(l2)] - jf(l3) NEXT:[read (Unit), r(1)] PREV:[r(true)] + r(true) NEXT:[r(1)] PREV:[r(while(true) { 1 if (2 > 3)..), jmp(l2)] l4: - r(1) NEXT:[r(2)] PREV:[jf(l3)] + r(1) NEXT:[r(2)] PREV:[r(true)] r(2) NEXT:[r(3)] PREV:[r(1)] r(3) NEXT:[r(>)] PREV:[r(2)] r(>) NEXT:[r(2 > 3)] PREV:[r(3)] @@ -464,7 +461,7 @@ l6: l7: jmp(l2) NEXT:[r(true)] PREV:[read (Unit)] l3: - read (Unit) NEXT:[r(2)] PREV:[jf(l3), jmp(l3)] + read (Unit) NEXT:[r(2)] PREV:[jmp(l3)] l8: r(2) NEXT:[] PREV:[read (Unit)] l1: diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt2166_kt2103.jet b/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt2166_kt2103.jet new file mode 100644 index 00000000000..1fadd54bb53 --- /dev/null +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt2166_kt2103.jet @@ -0,0 +1,17 @@ +package a + +//KT-2166 Control flow analysis doesn't detect that a 'while(true)' loop never terminates +fun foo(): Int { + while (true) { + } +} + +//KT-2103 Compiler requires return statement after loop which never exits +fun foo1() : Boolean{ + while(true){ + if (bar()) continue + return true + } +} + +fun bar() : Boolean = true \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/controlStructures/kt770.kt351.kt735_StatementType.jet b/compiler/testData/diagnostics/tests/controlStructures/kt770.kt351.kt735_StatementType.jet index 2612b5c6dce..185316295ed 100644 --- a/compiler/testData/diagnostics/tests/controlStructures/kt770.kt351.kt735_StatementType.jet +++ b/compiler/testData/diagnostics/tests/controlStructures/kt770.kt351.kt735_StatementType.jet @@ -118,8 +118,11 @@ fun bar(a: Unit) {} fun testStatementInExpressionContext() { var z = 34 val a1: Unit = z = 334 - val a2: Unit = while(true) {} val f = for (i in 1..10) {} if (true) return z = 34 - return while (true) {} + return while (true) {} } + +fun testStatementInExpressionContext2() { + val a2: Unit = while(true) {} +} \ No newline at end of file