Allow 'break' and 'continue' inside 'when' in 1.4+

This commit is contained in:
Dmitry Petrov
2019-08-20 17:47:51 +03:00
parent 55cb9561c2
commit f06f6f4660
9 changed files with 136 additions and 16 deletions
@@ -99,9 +99,14 @@ public class FirDiagnosticsSmokeTestGenerated extends AbstractFirDiagnosticsSmok
runTest("compiler/testData/diagnostics/tests/BreakContinue.kt");
}
@TestMetadata("BreakContinueInWhen.kt")
public void testBreakContinueInWhen() throws Exception {
runTest("compiler/testData/diagnostics/tests/BreakContinueInWhen.kt");
@TestMetadata("BreakContinueInWhen_after.kt")
public void testBreakContinueInWhen_after() throws Exception {
runTest("compiler/testData/diagnostics/tests/BreakContinueInWhen_after.kt");
}
@TestMetadata("BreakContinueInWhen_before.kt")
public void testBreakContinueInWhen_before() throws Exception {
runTest("compiler/testData/diagnostics/tests/BreakContinueInWhen_before.kt");
}
@TestMetadata("Builders.kt")
@@ -47,7 +47,6 @@ import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElementSelector
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingContextUtils
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.CompileTimeConstantUtils
import org.jetbrains.kotlin.resolve.bindingContextUtil.getEnclosingFunctionDescriptor
@@ -879,12 +878,14 @@ class ControlFlowProcessor(
if (loop == null) {
trace.report(BREAK_OR_CONTINUE_OUTSIDE_A_LOOP.on(expression))
} else {
val whenExpression = PsiTreeUtil.getParentOfType(
expression, KtWhenExpression::class.java, true,
KtLoopExpression::class.java
)
if (whenExpression != null) {
trace.report(BREAK_OR_CONTINUE_IN_WHEN.on(expression))
if (true != languageVersionSettings?.supportsFeature(LanguageFeature.AllowBreakAndContinueInsideWhen)) {
val whenExpression = PsiTreeUtil.getParentOfType(
expression, KtWhenExpression::class.java, true,
KtLoopExpression::class.java
)
if (whenExpression != null) {
trace.report(BREAK_OR_CONTINUE_IN_WHEN.on(expression))
}
}
}
}
@@ -0,0 +1,92 @@
// !LANGUAGE: +AllowBreakAndContinueInsideWhen
fun breakContinueInWhen(i: Int) {
for (y in 0..10) {
when(i) {
0 -> continue
1 -> break
2 -> {
for(z in 0..10) {
break
}
for(w in 0..10) {
continue
}
}
}
}
}
fun breakContinueInWhenWithWhile(i: Int, j: Int) {
while (i > 0) {
when (i) {
0 -> continue
1 -> break
2 -> {
while (j > 0) {
break
}
}
}
}
}
fun breakContinueInWhenWithDoWhile(i: Int, j: Int) {
do {
when (i) {
0 -> continue
1 -> break
2 -> {
do {
if (j == 5) break
if (j == 10) continue
} while (j > 0)
}
}
} while (i > 0)
}
fun labeledBreakContinue(i: Int) {
outer@ for (y in 0..10) {
when (i) {
0 -> continue@outer
1 -> break@outer
}
}
}
fun testBreakContinueInWhenInWhileCondition() {
var i = 0
while (
when (i) {
1 -> <!BREAK_OR_CONTINUE_OUTSIDE_A_LOOP!>break<!>
2 -> <!BREAK_OR_CONTINUE_OUTSIDE_A_LOOP!>continue<!>
else -> true
}
) {
++i
}
}
fun testBreakContinueInWhenInDoWhileCondition() {
var i = 0
do {
++i
} while (
when (i) {
1 -> <!BREAK_OR_CONTINUE_OUTSIDE_A_LOOP!>break<!>
2 -> <!BREAK_OR_CONTINUE_OUTSIDE_A_LOOP!>continue<!>
else -> true
}
)
}
fun testBreakContinueInWhenInForIteratorExpression(xs: List<Any>, i: Int) {
for (x in when (i) {
1 -> <!BREAK_OR_CONTINUE_OUTSIDE_A_LOOP!>break<!>
2 -> <!BREAK_OR_CONTINUE_OUTSIDE_A_LOOP!>continue<!>
else -> xs
}) {
}
}
@@ -0,0 +1,9 @@
package
public fun breakContinueInWhen(/*0*/ i: kotlin.Int): kotlin.Unit
public fun breakContinueInWhenWithDoWhile(/*0*/ i: kotlin.Int, /*1*/ j: kotlin.Int): kotlin.Unit
public fun breakContinueInWhenWithWhile(/*0*/ i: kotlin.Int, /*1*/ j: kotlin.Int): kotlin.Unit
public fun labeledBreakContinue(/*0*/ i: kotlin.Int): kotlin.Unit
public fun testBreakContinueInWhenInDoWhileCondition(): kotlin.Unit
public fun testBreakContinueInWhenInForIteratorExpression(/*0*/ xs: kotlin.collections.List<kotlin.Any>, /*1*/ i: kotlin.Int): kotlin.Unit
public fun testBreakContinueInWhenInWhileCondition(): kotlin.Unit
@@ -1,3 +1,5 @@
// !LANGUAGE: -AllowBreakAndContinueInsideWhen
fun breakContinueInWhen(i: Int) {
for (y in 0..10) {
when(i) {
@@ -101,9 +101,14 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
runTest("compiler/testData/diagnostics/tests/BreakContinue.kt");
}
@TestMetadata("BreakContinueInWhen.kt")
public void testBreakContinueInWhen() throws Exception {
runTest("compiler/testData/diagnostics/tests/BreakContinueInWhen.kt");
@TestMetadata("BreakContinueInWhen_after.kt")
public void testBreakContinueInWhen_after() throws Exception {
runTest("compiler/testData/diagnostics/tests/BreakContinueInWhen_after.kt");
}
@TestMetadata("BreakContinueInWhen_before.kt")
public void testBreakContinueInWhen_before() throws Exception {
runTest("compiler/testData/diagnostics/tests/BreakContinueInWhen_before.kt");
}
@TestMetadata("Builders.kt")
@@ -101,9 +101,14 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
runTest("compiler/testData/diagnostics/tests/BreakContinue.kt");
}
@TestMetadata("BreakContinueInWhen.kt")
public void testBreakContinueInWhen() throws Exception {
runTest("compiler/testData/diagnostics/tests/BreakContinueInWhen.kt");
@TestMetadata("BreakContinueInWhen_after.kt")
public void testBreakContinueInWhen_after() throws Exception {
runTest("compiler/testData/diagnostics/tests/BreakContinueInWhen_after.kt");
}
@TestMetadata("BreakContinueInWhen_before.kt")
public void testBreakContinueInWhen_before() throws Exception {
runTest("compiler/testData/diagnostics/tests/BreakContinueInWhen_before.kt");
}
@TestMetadata("Builders.kt")
@@ -106,6 +106,7 @@ enum class LanguageFeature(
ProhibitGenericArrayClassLiteral(KOTLIN_1_4),
NonParenthesizedAnnotationsOnFunctionalTypes(KOTLIN_1_4),
UseGetterNameForPropertyAnnotationsMethodOnJvm(KOTLIN_1_4),
AllowBreakAndContinueInsideWhen(KOTLIN_1_4),
ProperVisibilityForCompanionObjectInstanceField(sinceVersion = null, kind = BUG_FIX),
// Temporarily disabled, see KT-27084/KT-22379