From f06f6f4660a55ee0ef5302c6f6178e11647256dd Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Tue, 20 Aug 2019 17:47:51 +0300 Subject: [PATCH] Allow 'break' and 'continue' inside 'when' in 1.4+ --- .../fir/FirDiagnosticsSmokeTestGenerated.java | 11 ++- .../kotlin/cfg/ControlFlowProcessor.kt | 15 +-- .../tests/BreakContinueInWhen_after.kt | 92 +++++++++++++++++++ .../tests/BreakContinueInWhen_after.txt | 9 ++ ...nWhen.kt => BreakContinueInWhen_before.kt} | 2 + ...hen.txt => BreakContinueInWhen_before.txt} | 0 .../checkers/DiagnosticsTestGenerated.java | 11 ++- .../DiagnosticsUsingJavacTestGenerated.java | 11 ++- .../kotlin/config/LanguageVersionSettings.kt | 1 + 9 files changed, 136 insertions(+), 16 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/BreakContinueInWhen_after.kt create mode 100644 compiler/testData/diagnostics/tests/BreakContinueInWhen_after.txt rename compiler/testData/diagnostics/tests/{BreakContinueInWhen.kt => BreakContinueInWhen_before.kt} (96%) rename compiler/testData/diagnostics/tests/{BreakContinueInWhen.txt => BreakContinueInWhen_before.txt} (100%) diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsSmokeTestGenerated.java b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsSmokeTestGenerated.java index f79b536a549..6da87e893f0 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsSmokeTestGenerated.java +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsSmokeTestGenerated.java @@ -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") diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowProcessor.kt b/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowProcessor.kt index 84e9487bdf2..f9160fbad7b 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowProcessor.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowProcessor.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)) + } } } } diff --git a/compiler/testData/diagnostics/tests/BreakContinueInWhen_after.kt b/compiler/testData/diagnostics/tests/BreakContinueInWhen_after.kt new file mode 100644 index 00000000000..dc258660add --- /dev/null +++ b/compiler/testData/diagnostics/tests/BreakContinueInWhen_after.kt @@ -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 + 2 -> continue + else -> true + } + ) { + ++i + } +} + +fun testBreakContinueInWhenInDoWhileCondition() { + var i = 0 + do { + ++i + } while ( + when (i) { + 1 -> break + 2 -> continue + else -> true + } + ) +} + +fun testBreakContinueInWhenInForIteratorExpression(xs: List, i: Int) { + for (x in when (i) { + 1 -> break + 2 -> continue + else -> xs + }) { + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/BreakContinueInWhen_after.txt b/compiler/testData/diagnostics/tests/BreakContinueInWhen_after.txt new file mode 100644 index 00000000000..18be0f170ea --- /dev/null +++ b/compiler/testData/diagnostics/tests/BreakContinueInWhen_after.txt @@ -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, /*1*/ i: kotlin.Int): kotlin.Unit +public fun testBreakContinueInWhenInWhileCondition(): kotlin.Unit \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/BreakContinueInWhen.kt b/compiler/testData/diagnostics/tests/BreakContinueInWhen_before.kt similarity index 96% rename from compiler/testData/diagnostics/tests/BreakContinueInWhen.kt rename to compiler/testData/diagnostics/tests/BreakContinueInWhen_before.kt index 8d6e7af7fc5..b4cac631c45 100644 --- a/compiler/testData/diagnostics/tests/BreakContinueInWhen.kt +++ b/compiler/testData/diagnostics/tests/BreakContinueInWhen_before.kt @@ -1,3 +1,5 @@ +// !LANGUAGE: -AllowBreakAndContinueInsideWhen + fun breakContinueInWhen(i: Int) { for (y in 0..10) { when(i) { diff --git a/compiler/testData/diagnostics/tests/BreakContinueInWhen.txt b/compiler/testData/diagnostics/tests/BreakContinueInWhen_before.txt similarity index 100% rename from compiler/testData/diagnostics/tests/BreakContinueInWhen.txt rename to compiler/testData/diagnostics/tests/BreakContinueInWhen_before.txt diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 62e3be7bc91..2d70a6ad65c 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -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") diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java index c64432ceb2c..7fdd37091ce 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -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") diff --git a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt index db07a04a144..05a2cc80589 100644 --- a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt +++ b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.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