KT-1436 Allow break/continue in inlined lambdas
This commit is contained in:
committed by
teamcity
parent
ba7df005a1
commit
8ba80b4b7b
+12
@@ -5476,6 +5476,18 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/breakContinueInTryFinallyInLoop.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("breakContinueNoinline.kt")
|
||||
public void testBreakContinueNoinline() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/breakContinueNoinline.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("breakInLambdaPassedToDirectInvoke.kt")
|
||||
public void testBreakInLambdaPassedToDirectInvoke() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/breakInLambdaPassedToDirectInvoke.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("breakInsideLocal.kt")
|
||||
public void testBreakInsideLocal() throws Exception {
|
||||
|
||||
+12
@@ -5476,6 +5476,18 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/breakContinueInTryFinallyInLoop.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("breakContinueNoinline.kt")
|
||||
public void testBreakContinueNoinline() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/breakContinueNoinline.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("breakInLambdaPassedToDirectInvoke.kt")
|
||||
public void testBreakInLambdaPassedToDirectInvoke() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/breakInLambdaPassedToDirectInvoke.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("breakInsideLocal.kt")
|
||||
public void testBreakInsideLocal() throws Exception {
|
||||
|
||||
+28
-2
@@ -5,16 +5,21 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.analysis.checkers.expression
|
||||
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.FirElement
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression
|
||||
import org.jetbrains.kotlin.fir.resolvedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
|
||||
|
||||
object FirBreakOrContinueJumpsAcrossFunctionBoundaryChecker : FirLoopJumpChecker() {
|
||||
override fun check(expression: FirLoopJump, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val allowInlined = context.languageVersionSettings.supportsFeature(LanguageFeature.BreakContinueInInlineLambdas)
|
||||
val errorPathElements = ArrayDeque<FirElement>()
|
||||
|
||||
fun findPathAndCheck(element: FirElement?): Boolean {
|
||||
@@ -43,6 +48,7 @@ object FirBreakOrContinueJumpsAcrossFunctionBoundaryChecker : FirLoopJumpChecker
|
||||
}
|
||||
}
|
||||
}
|
||||
is FirLoop -> return findPathAndCheck(element.condition) || findPathAndCheck(element.block)
|
||||
is FirWhenExpression -> {
|
||||
for (branch in element.branches) {
|
||||
if (findPathAndCheck(branch.result)) {
|
||||
@@ -52,6 +58,21 @@ object FirBreakOrContinueJumpsAcrossFunctionBoundaryChecker : FirLoopJumpChecker
|
||||
}
|
||||
is FirVariable -> return findPathAndCheck(element.initializer)
|
||||
is FirWrappedExpression -> return findPathAndCheck(element.expression)
|
||||
is FirNoReceiverExpression -> return false
|
||||
is FirFunctionCall -> {
|
||||
if (findPathAndCheck(element.extensionReceiver) || findPathAndCheck(element.dispatchReceiver)) {
|
||||
return true
|
||||
}
|
||||
|
||||
val symbol = if (allowInlined) element.calleeReference.resolvedSymbol as? FirFunctionSymbol else null
|
||||
element.arguments.forEachIndexed { i, argument ->
|
||||
val expressionToCheck =
|
||||
if (symbol?.resolvedStatus?.isInline == true && !symbol.valueParameterSymbols[i].isNoinline) argument.tryInline() else argument
|
||||
if (findPathAndCheck(expressionToCheck)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
is FirCall -> {
|
||||
for (argument in element.arguments) {
|
||||
if (findPathAndCheck(argument)) {
|
||||
@@ -98,4 +119,9 @@ object FirBreakOrContinueJumpsAcrossFunctionBoundaryChecker : FirLoopJumpChecker
|
||||
|
||||
findPathAndCheck(expression.target.labeledElement.block)
|
||||
}
|
||||
|
||||
private fun FirExpression.tryInline(): FirExpression {
|
||||
val anonymousFunctionExpression = (((this as? FirLambdaArgumentExpression)?.expression) ?: this) as? FirAnonymousFunctionExpression
|
||||
return anonymousFunctionExpression?.anonymousFunction?.body ?: this
|
||||
}
|
||||
}
|
||||
+46
@@ -9033,6 +9033,52 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
public void testWhileTrueBreak() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/whileTrueBreak.kt");
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/inlinedBreakContinue")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class InlinedBreakContinue {
|
||||
@Test
|
||||
public void testAllFilesPresentInInlinedBreakContinue() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/inlinedBreakContinue"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("inlineFunctionWithMultipleParameters.kt")
|
||||
public void testInlineFunctionWithMultipleParameters() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/inlinedBreakContinue/inlineFunctionWithMultipleParameters.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("lambdaPassedToInlineFunction.kt")
|
||||
public void testLambdaPassedToInlineFunction() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/inlinedBreakContinue/lambdaPassedToInlineFunction.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("loopWithinInlineFunction.kt")
|
||||
public void testLoopWithinInlineFunction() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/inlinedBreakContinue/loopWithinInlineFunction.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/inlinedBreakContinue/simple.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("stdlibFunctions.kt")
|
||||
public void testStdlibFunctions() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/inlinedBreakContinue/stdlibFunctions.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("withReturnValue.kt")
|
||||
public void testWithReturnValue() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/inlinedBreakContinue/withReturnValue.kt");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
Generated
+18
@@ -1196,6 +1196,12 @@ public class Fir2IrTextTestGenerated extends AbstractFir2IrTextTest {
|
||||
runTest("compiler/testData/ir/irText/expressions/badBreakContinue.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("badInlinedBreakContinue.kt")
|
||||
public void testBadInlinedBreakContinue() throws Exception {
|
||||
runTest("compiler/testData/ir/irText/expressions/badInlinedBreakContinue.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("bangbang.kt")
|
||||
public void testBangbang() throws Exception {
|
||||
@@ -1238,6 +1244,12 @@ public class Fir2IrTextTestGenerated extends AbstractFir2IrTextTest {
|
||||
runTest("compiler/testData/ir/irText/expressions/breakContinueInLoopHeader.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("breakContinueInNoInlineLambda.kt")
|
||||
public void testBreakContinueInNoInlineLambda() throws Exception {
|
||||
runTest("compiler/testData/ir/irText/expressions/breakContinueInNoInlineLambda.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("breakContinueInWhen.kt")
|
||||
public void testBreakContinueInWhen() throws Exception {
|
||||
@@ -1502,6 +1514,12 @@ public class Fir2IrTextTestGenerated extends AbstractFir2IrTextTest {
|
||||
runTest("compiler/testData/ir/irText/expressions/incrementDecrement.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("inlinedBreakContinue.kt")
|
||||
public void testInlinedBreakContinue() throws Exception {
|
||||
runTest("compiler/testData/ir/irText/expressions/inlinedBreakContinue.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("interfaceThisRef.kt")
|
||||
public void testInterfaceThisRef() throws Exception {
|
||||
|
||||
+18
@@ -1196,6 +1196,12 @@ public class LightTreeFir2IrTextTestGenerated extends AbstractLightTreeFir2IrTex
|
||||
runTest("compiler/testData/ir/irText/expressions/badBreakContinue.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("badInlinedBreakContinue.kt")
|
||||
public void testBadInlinedBreakContinue() throws Exception {
|
||||
runTest("compiler/testData/ir/irText/expressions/badInlinedBreakContinue.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("bangbang.kt")
|
||||
public void testBangbang() throws Exception {
|
||||
@@ -1238,6 +1244,12 @@ public class LightTreeFir2IrTextTestGenerated extends AbstractLightTreeFir2IrTex
|
||||
runTest("compiler/testData/ir/irText/expressions/breakContinueInLoopHeader.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("breakContinueInNoInlineLambda.kt")
|
||||
public void testBreakContinueInNoInlineLambda() throws Exception {
|
||||
runTest("compiler/testData/ir/irText/expressions/breakContinueInNoInlineLambda.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("breakContinueInWhen.kt")
|
||||
public void testBreakContinueInWhen() throws Exception {
|
||||
@@ -1502,6 +1514,12 @@ public class LightTreeFir2IrTextTestGenerated extends AbstractLightTreeFir2IrTex
|
||||
runTest("compiler/testData/ir/irText/expressions/incrementDecrement.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("inlinedBreakContinue.kt")
|
||||
public void testInlinedBreakContinue() throws Exception {
|
||||
runTest("compiler/testData/ir/irText/expressions/inlinedBreakContinue.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("interfaceThisRef.kt")
|
||||
public void testInterfaceThisRef() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user