diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml
index b7c117d82c0..4fadbe817a5 100644
--- a/.idea/kotlinc.xml
+++ b/.idea/kotlinc.xml
@@ -8,4 +8,7 @@
-
+
+
+
+
\ No newline at end of file
diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java
index 45b2a0c396d..89d95a614cc 100644
--- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java
+++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java
@@ -5476,6 +5476,18 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
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 {
diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java
index b7f16f68cfb..f15c93bdf3c 100644
--- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java
+++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java
@@ -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 {
diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java
index 6c409c6930d..b5df4f232bf 100644
--- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java
+++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java
@@ -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 {
diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirBreakOrContinueJumpsAcrossFunctionBoundaryChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirBreakOrContinueJumpsAcrossFunctionBoundaryChecker.kt
index 574a1b46887..85259a56e9b 100644
--- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirBreakOrContinueJumpsAcrossFunctionBoundaryChecker.kt
+++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirBreakOrContinueJumpsAcrossFunctionBoundaryChecker.kt
@@ -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()
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
+ }
}
\ No newline at end of file
diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java
index 11adbb23903..d357fe5d48f 100644
--- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java
+++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java
@@ -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
diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/Fir2IrTextTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/Fir2IrTextTestGenerated.java
index 6d54b3b5fee..18a257fd94e 100644
--- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/Fir2IrTextTestGenerated.java
+++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/Fir2IrTextTestGenerated.java
@@ -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 {
diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/LightTreeFir2IrTextTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/LightTreeFir2IrTextTestGenerated.java
index 9b7c5256d3d..7b4b096147a 100644
--- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/LightTreeFir2IrTextTestGenerated.java
+++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/LightTreeFir2IrTextTestGenerated.java
@@ -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 {
diff --git a/compiler/frontend/cfg/src/org/jetbrains/kotlin/cfg/ControlFlowProcessor.kt b/compiler/frontend/cfg/src/org/jetbrains/kotlin/cfg/ControlFlowProcessor.kt
index 95b29fc9de2..ed015f875b8 100644
--- a/compiler/frontend/cfg/src/org/jetbrains/kotlin/cfg/ControlFlowProcessor.kt
+++ b/compiler/frontend/cfg/src/org/jetbrains/kotlin/cfg/ControlFlowProcessor.kt
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.AccessTarget
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.InstructionWithValue
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.MagicKind
import org.jetbrains.kotlin.config.LanguageFeature
+import org.jetbrains.kotlin.config.LanguageFeature.BreakContinueInInlineLambdas
import org.jetbrains.kotlin.config.LanguageFeature.ProhibitQualifiedAccessToUninitializedEnumEntry
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
@@ -926,9 +927,9 @@ class ControlFlowProcessor(
private fun jumpDoesNotCrossFunctionBoundary(jumpExpression: KtExpressionWithLabel, jumpTarget: KtLoopExpression): Boolean {
val bindingContext = trace.bindingContext
-
- val labelExprEnclosingFunc = getEnclosingFunctionDescriptor(bindingContext, jumpExpression)
- val labelTargetEnclosingFunc = getEnclosingFunctionDescriptor(bindingContext, jumpTarget)
+ val skipInlineFunctions = languageVersionSettings.supportsFeature(BreakContinueInInlineLambdas)
+ val labelExprEnclosingFunc = getEnclosingFunctionDescriptor(bindingContext, jumpExpression, skipInlineFunctions)
+ val labelTargetEnclosingFunc = getEnclosingFunctionDescriptor(bindingContext, jumpTarget, skipInlineFunctions)
return if (labelExprEnclosingFunc !== labelTargetEnclosingFunc) {
// Check to report only once
if (builder.getLoopExitPoint(jumpTarget) != null ||
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/bindingContextUtil/BindingContextUtils.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/bindingContextUtil/BindingContextUtils.kt
index d5c3404e009..030af2c0234 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/bindingContextUtil/BindingContextUtils.kt
+++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/bindingContextUtil/BindingContextUtils.kt
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor
import org.jetbrains.kotlin.psi.*
+import org.jetbrains.kotlin.psi.KtPsiUtil.deparenthesizeOnce
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
import org.jetbrains.kotlin.resolve.BindingContext
@@ -32,6 +33,7 @@ import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
+import org.jetbrains.kotlin.resolve.calls.util.getResolvedCall
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
import org.jetbrains.kotlin.resolve.scopes.utils.takeSnapshot
import org.jetbrains.kotlin.types.KotlinType
@@ -154,12 +156,49 @@ fun getEnclosingDescriptor(context: BindingContext, element: KtElement): Declara
}
}
-fun getEnclosingFunctionDescriptor(context: BindingContext, element: KtElement): FunctionDescriptor? {
- val functionOrClass = element.getParentOfTypeCodeFragmentAware(KtFunction::class.java, KtClassOrObject::class.java)
- val descriptor = context.get(DECLARATION_TO_DESCRIPTOR, functionOrClass)
- return if (functionOrClass is KtFunction) {
- if (descriptor is FunctionDescriptor) descriptor else null
- } else {
- if (descriptor is ClassDescriptor) descriptor.unsubstitutedPrimaryConstructor else null
+fun getEnclosingFunctionDescriptor(context: BindingContext, element: KtElement, skipInlineFunctionLiterals: Boolean): FunctionDescriptor? {
+ var current = element
+ while (true) {
+ val functionOrClass = current.getParentOfTypeCodeFragmentAware(KtFunction::class.java, KtClassOrObject::class.java)
+ val descriptor = context.get(DECLARATION_TO_DESCRIPTOR, functionOrClass)
+ if (functionOrClass is KtFunction) {
+ if (descriptor is FunctionDescriptor) {
+ if (skipInlineFunctionLiterals && isInlineableFunctionLiteral(
+ ((functionOrClass as? KtFunctionLiteral)?.parent as? KtExpression) ?: functionOrClass,
+ context
+ )) {
+ current = functionOrClass
+ } else {
+ return descriptor
+ }
+ } else {
+ return null
+ }
+ } else {
+ return if (descriptor is ClassDescriptor) descriptor.unsubstitutedPrimaryConstructor else null
+ }
}
}
+
+fun isInlineableFunctionLiteral(expression: KtExpression, context: BindingContext): Boolean {
+ if (expression !is KtLambdaExpression && !(expression is KtNamedFunction && expression.name == null)) {
+ return false
+ }
+ var wrapper: PsiElement = expression
+ while (deparenthesizeOnce(wrapper.parent as? KtExpression) == wrapper) {
+ wrapper = wrapper.parent
+ }
+
+ val argument = (wrapper.parent as? KtValueArgument) ?: return false
+ val call = (((argument.parent as? KtValueArgumentList) ?: argument).parent as? KtCallExpression) ?: return false
+ val resolvedCall = call.getResolvedCall(context) ?: return false
+ val descriptor = (resolvedCall.resultingDescriptor as? FunctionDescriptor) ?: return false
+ if (descriptor.isInline) {
+ val parameter = resolvedCall.valueArguments.entries.find { (_, valueArgument) ->
+ valueArgument.arguments.any { it.asElement() == argument }
+ }?.key ?: return false
+ return !parameter.isNoinline
+ }
+
+ return false
+}
\ No newline at end of file
diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/inline/DeepCopyIrTreeWithDescriptors.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/inline/DeepCopyIrTreeWithDescriptors.kt
index 7fc8a696ec4..b086990fa13 100644
--- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/inline/DeepCopyIrTreeWithDescriptors.kt
+++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/inline/DeepCopyIrTreeWithDescriptors.kt
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.ir.declarations.IrDeclarationParent
import org.jetbrains.kotlin.ir.declarations.IrTypeParametersContainer
import org.jetbrains.kotlin.ir.declarations.copyAttributes
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
+import org.jetbrains.kotlin.ir.expressions.IrLoop
import org.jetbrains.kotlin.ir.expressions.IrTypeOperatorCall
import org.jetbrains.kotlin.ir.expressions.impl.IrTypeOperatorCallImpl
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/DirectInvokeLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/DirectInvokeLowering.kt
index c292d586b83..8b2c68b3658 100644
--- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/DirectInvokeLowering.kt
+++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/DirectInvokeLowering.kt
@@ -73,7 +73,7 @@ private class DirectInvokeLowering(private val context: JvmBackendContext) : Fil
return context.createIrBuilder(scope.scopeOwnerSymbol).run {
at(expression)
irBlock {
- val arguments = function.explicitParameters.withIndex().map { (index, parameter) ->
+ val arguments = function.explicitParameters.mapIndexed { index, parameter ->
val argument = expression.getValueArgument(index)!!
IrVariableImpl(
argument.startOffset, argument.endOffset, IrDeclarationOrigin.DEFINED, IrVariableSymbolImpl(), parameter.name,
diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/BodyGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/BodyGenerator.kt
index a85a5449f2e..d2f2298edb2 100644
--- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/BodyGenerator.kt
+++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/BodyGenerator.kt
@@ -39,10 +39,15 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.isUnit
+interface LoopResolver {
+ fun getLoop(expression: KtExpression): IrLoop?
+}
+
class BodyGenerator(
val scopeOwnerSymbol: IrSymbol,
- override val context: GeneratorContext
-) : GeneratorWithScope {
+ override val context: GeneratorContext,
+ private val parentLoopResolver: LoopResolver?
+) : GeneratorWithScope, LoopResolver {
val scopeOwner: DeclarationDescriptor get() = scopeOwnerSymbol.descriptor
@@ -196,8 +201,9 @@ class BodyGenerator(
loopTable[expression] = irLoop
}
- fun getLoop(expression: KtExpression): IrLoop? =
- loopTable[expression]
+ override fun getLoop(expression: KtExpression): IrLoop? {
+ return loopTable[expression] ?: parentLoopResolver?.getLoop(expression)
+ }
fun generatePrimaryConstructorBody(ktClassOrObject: KtPureClassOrObject, irConstructor: IrConstructor): IrBody {
val irBlockBody = context.irFactory.createBlockBody(ktClassOrObject.pureStartOffset, ktClassOrObject.pureEndOffset)
diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DeclarationGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DeclarationGenerator.kt
index 22f464ec8a0..a04713a05f5 100644
--- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DeclarationGenerator.kt
+++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DeclarationGenerator.kt
@@ -46,7 +46,7 @@ class DeclarationGenerator(override val context: GeneratorContext) : Generator {
return try {
when (ktDeclaration) {
is KtNamedFunction ->
- FunctionGenerator(this).generateFunctionDeclaration(ktDeclaration)
+ FunctionGenerator(this).generateFunctionDeclaration(ktDeclaration, null)
is KtProperty ->
PropertyGenerator(this).generatePropertyDeclaration(ktDeclaration)
is KtClassOrObject ->
@@ -207,5 +207,5 @@ abstract class DeclarationGeneratorExtension(val declarationGenerator: Declarati
fun KotlinType.toIrType() = with(declarationGenerator) { toIrType() }
}
-fun Generator.createBodyGenerator(scopeOwnerSymbol: IrSymbol) =
- BodyGenerator(scopeOwnerSymbol, context)
+fun Generator.createBodyGenerator(scopeOwnerSymbol: IrSymbol, parentLoopResolver: LoopResolver? = null) =
+ BodyGenerator(scopeOwnerSymbol, context, parentLoopResolver)
diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/FunctionGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/FunctionGenerator.kt
index 50a73316703..b2fff9dff5e 100644
--- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/FunctionGenerator.kt
+++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/FunctionGenerator.kt
@@ -40,6 +40,7 @@ class FunctionGenerator(declarationGenerator: DeclarationGenerator) : Declaratio
@JvmOverloads
fun generateFunctionDeclaration(
ktFunction: KtNamedFunction,
+ parentLoopResolver: LoopResolver?,
origin: IrDeclarationOrigin = IrDeclarationOrigin.DEFINED
): IrSimpleFunction =
declareSimpleFunction(
@@ -47,19 +48,21 @@ class FunctionGenerator(declarationGenerator: DeclarationGenerator) : Declaratio
ktFunction.receiverTypeReference,
ktFunction.contextReceivers.mapNotNull { it.typeReference() },
origin,
- getOrFail(BindingContext.FUNCTION, ktFunction)
+ getOrFail(BindingContext.FUNCTION, ktFunction),
+ parentLoopResolver
) {
ktFunction.bodyExpression?.let { generateFunctionBody(it) }
}
- fun generateLambdaFunctionDeclaration(ktFunction: KtFunctionLiteral): IrSimpleFunction {
+ fun generateLambdaFunctionDeclaration(ktFunction: KtFunctionLiteral, parentLoopResolver: LoopResolver?): IrSimpleFunction {
val lambdaDescriptor = getOrFail(BindingContext.FUNCTION, ktFunction)
return declareSimpleFunction(
ktFunction,
null,
emptyList(),
IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA,
- lambdaDescriptor
+ lambdaDescriptor,
+ parentLoopResolver
) {
generateLambdaBody(ktFunction, lambdaDescriptor)
}
@@ -80,11 +83,12 @@ class FunctionGenerator(declarationGenerator: DeclarationGenerator) : Declaratio
ktContextReceivers: List,
origin: IrDeclarationOrigin,
descriptor: FunctionDescriptor,
+ parentLoopResolver: LoopResolver?,
generateBody: BodyGenerator.() -> IrBody?
): IrSimpleFunction =
declareSimpleFunctionInner(descriptor, ktFunction, origin).buildWithScope { irFunction ->
generateFunctionParameterDeclarationsAndReturnType(irFunction, ktFunction, ktReceiver, ktContextReceivers)
- irFunction.body = createBodyGenerator(irFunction.symbol).generateBody()
+ irFunction.body = createBodyGenerator(irFunction.symbol, parentLoopResolver).generateBody()
}
private fun declareSimpleFunctionInner(
diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/LocalFunctionGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/LocalFunctionGenerator.kt
index 566d8a3f7da..c1534e47e22 100644
--- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/LocalFunctionGenerator.kt
+++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/LocalFunctionGenerator.kt
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.psi2ir.generators
+import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
@@ -24,13 +25,19 @@ import org.jetbrains.kotlin.psi.KtLambdaExpression
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset
+import org.jetbrains.kotlin.resolve.bindingContextUtil.isInlineableFunctionLiteral
class LocalFunctionGenerator(statementGenerator: StatementGenerator) : StatementGeneratorExtension(statementGenerator) {
fun generateLambda(ktLambda: KtLambdaExpression): IrStatement {
val ktFun = ktLambda.functionLiteral
val lambdaExpressionType = getTypeInferredByFrontendOrFail(ktLambda).toIrType()
- val irLambdaFunction = FunctionGenerator(context).generateLambdaFunctionDeclaration(ktFun)
+ val loopResolver = if (context.languageVersionSettings.supportsFeature(LanguageFeature.BreakContinueInInlineLambdas)
+ && isInlineableFunctionLiteral(ktLambda, context.bindingContext)
+ )
+ statementGenerator.bodyGenerator
+ else null
+ val irLambdaFunction = FunctionGenerator(context).generateLambdaFunctionDeclaration(ktFun, loopResolver)
return IrFunctionExpressionImpl(
ktLambda.startOffset, ktLambda.endOffset,
@@ -54,5 +61,12 @@ class LocalFunctionGenerator(statementGenerator: StatementGenerator) : Statement
}
private fun generateFunctionDeclaration(ktFun: KtNamedFunction) =
- FunctionGenerator(context).generateFunctionDeclaration(ktFun, IrDeclarationOrigin.LOCAL_FUNCTION)
+ FunctionGenerator(context).generateFunctionDeclaration(
+ ktFun,
+ if (context.languageVersionSettings.supportsFeature(LanguageFeature.BreakContinueInInlineLambdas)
+ && isInlineableFunctionLiteral(ktFun, context.bindingContext)
+ ) statementGenerator.bodyGenerator
+ else null,
+ IrDeclarationOrigin.LOCAL_FUNCTION
+ )
}
\ No newline at end of file
diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ScriptGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ScriptGenerator.kt
index fda4a0dcd90..3d8bfcecd2f 100644
--- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ScriptGenerator.kt
+++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ScriptGenerator.kt
@@ -168,7 +168,8 @@ class ScriptGenerator(declarationGenerator: DeclarationGenerator) : DeclarationG
is KtScriptInitializer -> {
val irExpressionBody = BodyGenerator(
irScript.symbol,
- context
+ context,
+ null
).generateExpressionBody(d.body!!)
if (d == ktScript.declarations.last() && descriptor.resultValue != null) {
descriptor.resultValue!!.let { resultDescriptor ->
@@ -194,7 +195,7 @@ class ScriptGenerator(declarationGenerator: DeclarationGenerator) : DeclarationG
is KtDestructuringDeclaration -> {
// copied with modifications from StatementGenerator.visitDestructuringDeclaration
// TODO: consider code deduplication
- val bodyGenerator = BodyGenerator(irScript.symbol, context)
+ val bodyGenerator = BodyGenerator(irScript.symbol, context, null)
val statementGenerator = bodyGenerator.createStatementGenerator()
val irBlock = IrCompositeImpl(
d.startOffsetSkippingComments, d.endOffset,
diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/DeepCopyIrTreeWithDeclarations.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/DeepCopyIrTreeWithDeclarations.kt
index b1708b47957..35387484050 100644
--- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/DeepCopyIrTreeWithDeclarations.kt
+++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/DeepCopyIrTreeWithDeclarations.kt
@@ -5,7 +5,6 @@
package org.jetbrains.kotlin.ir
-import org.jetbrains.kotlin.ir.expressions.IrLoop
import org.jetbrains.kotlin.ir.util.DeepCopyIrTreeWithSymbols
import org.jetbrains.kotlin.ir.util.DeepCopySymbolRemapper
import org.jetbrains.kotlin.ir.util.DeepCopyTypeRemapper
@@ -19,12 +18,5 @@ fun T.deepCopyWithVariables(): T {
val typesRemapper = DeepCopyTypeRemapper(symbolsRemapper)
- return this.transform(
- object : DeepCopyIrTreeWithSymbols(symbolsRemapper, typesRemapper) {
- override fun getNonTransformedLoop(irLoop: IrLoop): IrLoop {
- return irLoop
- }
- },
- null
- ) as T
+ return this.transform(DeepCopyIrTreeWithSymbols(symbolsRemapper, typesRemapper), null) as T
}
diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopyIrTreeWithSymbols.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopyIrTreeWithSymbols.kt
index 17086b2dcdd..275e660bdaf 100644
--- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopyIrTreeWithSymbols.kt
+++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopyIrTreeWithSymbols.kt
@@ -738,10 +738,7 @@ open class DeepCopyIrTreeWithSymbols(
private val transformedLoops = HashMap()
private fun getTransformedLoop(irLoop: IrLoop): IrLoop =
- transformedLoops.getOrElse(irLoop) { getNonTransformedLoop(irLoop) }
-
- protected open fun getNonTransformedLoop(irLoop: IrLoop): IrLoop =
- throw AssertionError("Outer loop was not transformed: ${irLoop.render()}")
+ transformedLoops.getOrDefault(irLoop, irLoop)
override fun visitWhileLoop(loop: IrWhileLoop): IrWhileLoop =
IrWhileLoopImpl(loop.startOffset, loop.endOffset, loop.type.remapType(), mapStatementOrigin(loop.origin)).also { newLoop ->
diff --git a/compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/inlinedBreakContinue/inlineFunctionWithMultipleParameters.kt b/compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/inlinedBreakContinue/inlineFunctionWithMultipleParameters.kt
new file mode 100644
index 00000000000..1d14ef49c52
--- /dev/null
+++ b/compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/inlinedBreakContinue/inlineFunctionWithMultipleParameters.kt
@@ -0,0 +1,35 @@
+// LANGUAGE: +BreakContinueInInlineLambdas
+// TARGET_BACKEND: JVM_IR
+// TARGET_BACKEND: JS_IR
+// TARGET_BACKEND: JS_IR_ES6
+// TARGET_BACKEND: NATIVE
+// TARGET_BACKEND: WASM
+// WITH_STDLIB
+
+import kotlin.test.assertEquals
+
+inline fun foo(
+ block1: () -> Unit,
+ noinline block2: () -> Unit,
+ block3: () -> Unit
+) {
+ block1()
+ block2()
+ block3()
+}
+
+fun box(): String {
+ val visited = mutableListOf()
+
+ for (i in 1..3) {
+ foo(
+ { visited += 1; if (i == 1) continue },
+ { visited += 2 },
+ { visited += 3; if (i == 2) break },
+ )
+ }
+
+ assertEquals(listOf(1, 1, 2, 3), visited)
+
+ return "OK"
+}
\ No newline at end of file
diff --git a/compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/inlinedBreakContinue/lambdaPassedToInlineFunction.kt b/compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/inlinedBreakContinue/lambdaPassedToInlineFunction.kt
new file mode 100644
index 00000000000..8a13eff0b4d
--- /dev/null
+++ b/compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/inlinedBreakContinue/lambdaPassedToInlineFunction.kt
@@ -0,0 +1,65 @@
+// LANGUAGE: +BreakContinueInInlineLambdas
+// TARGET_BACKEND: JVM_IR
+// TARGET_BACKEND: JS_IR
+// TARGET_BACKEND: JS_IR_ES6
+// TARGET_BACKEND: NATIVE
+// TARGET_BACKEND: WASM
+// WITH_STDLIB
+
+import kotlin.test.assertEquals
+
+@Target(AnnotationTarget.EXPRESSION)
+@Retention(AnnotationRetention.SOURCE)
+public annotation class SomeAnnotation
+
+inline fun foo(block: () -> Unit) = block()
+
+fun box(): String {
+ val visited = mutableListOf>()
+
+ var i = 0
+ outer@ while (true) {
+ i += 1
+ inner@ for (j in 1..10) {
+ foo(
+ (@SomeAnnotation
+ fun() {
+ foo(fun() {
+ foo(@SomeAnnotation {
+ foo {
+ if (i == 2) {
+ continue@outer
+ }
+
+ if (i == 4) {
+ break@outer
+ }
+
+ if (j == 2) {
+ continue
+ }
+
+ if (j == 4) {
+ continue@inner
+ }
+
+ if (j == 6 && i == 1) {
+ break@inner
+ }
+
+ if (j == 6 && i == 3) {
+ break
+ }
+ }
+ })
+ })
+ })
+ )
+ visited += i to j
+ }
+ }
+
+ assertEquals(listOf(1 to 1, 1 to 3, 1 to 5, 3 to 1, 3 to 3, 3 to 5), visited)
+
+ return "OK"
+}
\ No newline at end of file
diff --git a/compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/inlinedBreakContinue/loopWithinInlineFunction.kt b/compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/inlinedBreakContinue/loopWithinInlineFunction.kt
new file mode 100644
index 00000000000..d588d1e98ee
--- /dev/null
+++ b/compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/inlinedBreakContinue/loopWithinInlineFunction.kt
@@ -0,0 +1,30 @@
+// LANGUAGE: +BreakContinueInInlineLambdas
+// TARGET_BACKEND: JVM_IR
+// TARGET_BACKEND: JS_IR
+// TARGET_BACKEND: JS_IR_ES6
+// TARGET_BACKEND: NATIVE
+// TARGET_BACKEND: WASM
+// WITH_STDLIB
+
+import kotlin.test.assertEquals
+
+inline fun Iterable.myForEach(action: (T) -> Unit): Unit {
+ for (element in this) action(element)
+}
+
+
+fun box(): String {
+ val visited = mutableListOf>()
+
+ for (i in 1..3) {
+ (1..3).myForEach { j ->
+ if (j == 3) {
+ break
+ }
+ visited += i to j
+ }
+ }
+
+ assertEquals(listOf(1 to 1, 1 to 2), visited)
+ return "OK"
+}
\ No newline at end of file
diff --git a/compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/inlinedBreakContinue/simple.kt b/compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/inlinedBreakContinue/simple.kt
new file mode 100644
index 00000000000..0f545f12028
--- /dev/null
+++ b/compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/inlinedBreakContinue/simple.kt
@@ -0,0 +1,17 @@
+// LANGUAGE: +BreakContinueInInlineLambdas
+// TARGET_BACKEND: JVM_IR
+// TARGET_BACKEND: JS_IR
+// TARGET_BACKEND: JS_IR_ES6
+// TARGET_BACKEND: NATIVE
+// TARGET_BACKEND: WASM
+
+inline fun foo(block: () -> Unit) { block() }
+
+fun box(): String {
+ while (true) {
+ foo { break }
+ return "FAIL"
+ }
+
+ return "OK"
+}
\ No newline at end of file
diff --git a/compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/inlinedBreakContinue/stdlibFunctions.kt b/compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/inlinedBreakContinue/stdlibFunctions.kt
new file mode 100644
index 00000000000..4079cd6cc64
--- /dev/null
+++ b/compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/inlinedBreakContinue/stdlibFunctions.kt
@@ -0,0 +1,22 @@
+// LANGUAGE: +BreakContinueInInlineLambdas
+// TARGET_BACKEND: JVM_IR
+// TARGET_BACKEND: JS_IR
+// TARGET_BACKEND: JS_IR_ES6
+// TARGET_BACKEND: NATIVE
+// TARGET_BACKEND: WASM
+// WITH_STDLIB
+
+import kotlin.test.assertEquals
+
+inline fun Iterable.myForEach(action: (T) -> Unit): Unit {
+ for (element in this) action(element)
+}
+
+
+fun box(): String {
+ while (true) {
+ "".let { it.run { break } }
+ }
+
+ return "OK"
+}
\ No newline at end of file
diff --git a/compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/inlinedBreakContinue/withReturnValue.kt b/compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/inlinedBreakContinue/withReturnValue.kt
new file mode 100644
index 00000000000..2770f282139
--- /dev/null
+++ b/compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/inlinedBreakContinue/withReturnValue.kt
@@ -0,0 +1,18 @@
+// LANGUAGE: +BreakContinueInInlineLambdas
+// TARGET_BACKEND: JVM_IR
+// TARGET_BACKEND: JS_IR
+// TARGET_BACKEND: JS_IR_ES6
+// TARGET_BACKEND: NATIVE
+// TARGET_BACKEND: WASM
+
+inline fun foo(block: () -> Int): Int = block()
+
+fun box(): String {
+ var sum = 0
+
+ for (i in 1..10) {
+ sum += foo { if (i == 3) break else i }
+ }
+
+ return if (sum == 3) "OK" else "FAIL"
+}
\ No newline at end of file
diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/breakContinueNoinline.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/breakContinueNoinline.kt
new file mode 100644
index 00000000000..b02fa55e63b
--- /dev/null
+++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/breakContinueNoinline.kt
@@ -0,0 +1,21 @@
+// FIR_IDENTICAL
+// LANGUAGE: +BreakContinueInInlineLambdas
+
+
+inline fun notInlining(noinline block1: () -> Unit, block2: () -> Unit) {
+ block1()
+ block2()
+}
+
+fun test() {
+ label@ while(true) {
+ notInlining({ break }) {}
+ notInlining({ continue }) {}
+ notInlining(fun () { break }) {}
+ notInlining(fun () { continue }) {}
+ notInlining({ break@label }) {}
+ notInlining({ continue@label }) {}
+ notInlining(fun () { break@label }) {}
+ notInlining(fun () { continue@label }) {}
+ }
+}
diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/breakContinueNoinline.txt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/breakContinueNoinline.txt
new file mode 100644
index 00000000000..016e089b89b
--- /dev/null
+++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/breakContinueNoinline.txt
@@ -0,0 +1,5 @@
+package
+
+public inline fun notInlining(/*0*/ noinline block1: () -> kotlin.Unit, /*1*/ block2: () -> kotlin.Unit): kotlin.Unit
+public fun test(): kotlin.Unit
+
diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/breakInLambdaPassedToDirectInvoke.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/breakInLambdaPassedToDirectInvoke.kt
new file mode 100644
index 00000000000..01707eea017
--- /dev/null
+++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/breakInLambdaPassedToDirectInvoke.kt
@@ -0,0 +1,10 @@
+// FIR_IDENTICAL
+// LANGUAGE: +BreakContinueInInlineLambdas
+
+fun test() {
+ while(true) {
+ {block: () -> Unit -> block()}(
+ {break}
+ )
+ }
+}
\ No newline at end of file
diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/breakInLambdaPassedToDirectInvoke.txt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/breakInLambdaPassedToDirectInvoke.txt
new file mode 100644
index 00000000000..93e27f34c8c
--- /dev/null
+++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/breakInLambdaPassedToDirectInvoke.txt
@@ -0,0 +1,3 @@
+package
+
+public fun test(): kotlin.Unit
diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/breakInsideLocal.fir.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/breakInsideLocal.fir.kt
index 3ca844f3c3e..5840d975314 100644
--- a/compiler/testData/diagnostics/tests/controlFlowAnalysis/breakInsideLocal.fir.kt
+++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/breakInsideLocal.fir.kt
@@ -1,38 +1,77 @@
+// LANGUAGE: +BreakContinueInInlineLambdas
+
+inline fun foo(block: () -> T): T = block()
+
+
+@Target(AnnotationTarget.EXPRESSION)
+@Retention(AnnotationRetention.SOURCE)
+public annotation class SomeAnnotation
+
fun test() {
while (true) {
- fun local1() {
- break
+ fun local1(tag: Int) {
+ when(tag) {
+ 0 -> break
+ 1 -> foo { break }
+ 2 -> foo(@SomeAnnotation { break })
+ 3 -> foo(fun () { break })
+ 4 -> foo(@SomeAnnotation fun () { break })
+ }
}
}
}
fun test2() {
while (true) {
- {
- continue
+ {tag: Int ->
+ when(tag) {
+ 0 -> continue
+ 1 -> foo { continue }
+ 2 -> foo(@SomeAnnotation { continue })
+ 3 -> foo(fun () { continue })
+ 4 -> foo(@SomeAnnotation fun () { continue })
+ }
}
}
}
fun test3() {
while (true) {
- class LocalClass {
+ class LocalClass(val tag: Int) {
init {
- continue
+ when(tag) {
+ 0 -> continue
+ 1 -> foo { continue }
+ 2 -> foo(@SomeAnnotation { continue })
+ 3 -> foo(fun () { continue })
+ 4 -> foo(@SomeAnnotation fun () { continue })
+ }
}
fun foo() {
- break
+ when(tag) {
+ 0 -> break
+ 1 -> foo { break }
+ 2 -> foo(@SomeAnnotation { break })
+ 3 -> foo(fun () { break })
+ 4 -> foo(@SomeAnnotation fun () { break })
+ }
}
}
}
}
-fun test4() {
+fun test4(tag: Int) {
while (true) {
object: Any() {
init {
- break
+ when(tag) {
+ 0 -> break
+ 1 -> foo { break }
+ 2 -> foo(@SomeAnnotation { break })
+ 3 -> foo(fun () { break })
+ 4 -> foo(@SomeAnnotation fun () { break })
+ }
}
}
}
@@ -40,12 +79,15 @@ fun test4() {
fun test5() {
while (true) {
- class LocalClass(val x: Int) {
- constructor() : this(42) {
- break
- }
- constructor(y: Double) : this(y.toInt()) {
- continue
+ class LocalClass(val s: String) {
+ constructor(tag: Int) : this("") {
+ when(tag) {
+ 0 -> break
+ 1 -> foo { break }
+ 2 -> foo(@SomeAnnotation { break })
+ 3 -> foo(fun () { break })
+ 4 -> foo(@SomeAnnotation fun () { break })
+ }
}
}
}
@@ -53,12 +95,24 @@ fun test5() {
fun test6() {
while (true) {
- class LocalClass(val x: Int) {
+ class LocalClass(val tag: Int) {
init {
- break
+ when(tag) {
+ 0 -> break
+ 1 -> foo { break }
+ 2 -> foo(@SomeAnnotation { break })
+ 3 -> foo(fun () { break })
+ 4 -> foo(@SomeAnnotation fun () { break })
+ }
}
init {
- continue
+ when(tag) {
+ 0 -> continue
+ 1 -> foo { continue }
+ 2 -> foo(@SomeAnnotation { continue })
+ 3 -> foo(fun () { continue })
+ 4 -> foo(@SomeAnnotation fun () { continue })
+ }
}
}
}
@@ -66,12 +120,26 @@ fun test6() {
fun test7() {
while (true) {
- class LocalClass {
+ class LocalClass(val tag: Int) {
val x: Int = if (true) {
- break
+ when(tag) {
+ 0 -> break
+ 1 -> foo { break }
+ 2 -> foo(@SomeAnnotation { break })
+ 3 -> foo(fun (): Int { break })
+ 4 -> foo(@SomeAnnotation fun (): Int { break })
+ else -> 1
+ }
}
else {
- continue
+ when(tag) {
+ 0 -> continue
+ 1 -> foo { continue }
+ 2 -> foo(@SomeAnnotation { continue })
+ 3 -> foo(fun (): Int { continue })
+ 4 -> foo(@SomeAnnotation fun (): Int { continue })
+ else -> 2
+ }
}
}
}
@@ -80,7 +148,16 @@ fun test7() {
fun test8() {
while (true) {
class LocalClass(val x: Int) {
- constructor() : this(if (true) { 42 } else { break })
+ constructor(tag: Int, unused: Boolean) : this(
+ when(tag) {
+ 0 -> break
+ 1 -> foo { break }
+ 2 -> foo(@SomeAnnotation { break })
+ 3 -> foo(fun (): Int { break })
+ 4 -> foo(@SomeAnnotation fun (): Int { break })
+ else -> 1
+ }
+ )
}
}
-}
+}
\ No newline at end of file
diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/breakInsideLocal.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/breakInsideLocal.kt
index 170a379cf7b..a04c76504e1 100644
--- a/compiler/testData/diagnostics/tests/controlFlowAnalysis/breakInsideLocal.kt
+++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/breakInsideLocal.kt
@@ -1,38 +1,77 @@
+// LANGUAGE: +BreakContinueInInlineLambdas
+
+inline fun foo(block: () -> T): T = block()
+
+
+@Target(AnnotationTarget.EXPRESSION)
+@Retention(AnnotationRetention.SOURCE)
+public annotation class SomeAnnotation
+
fun test() {
while (true) {
- fun local1() {
- break
+ fun local1(tag: Int) {
+ when(tag) {
+ 0 -> break
+ 1 -> foo { break }
+ 2 -> foo(@SomeAnnotation { break })
+ 3 -> foo(fun () { break })
+ 4 -> foo(@SomeAnnotation fun () { break })
+ }
}
}
}
fun test2() {
while (true) {
- {
- continue
+ {tag: Int ->
+ when(tag) {
+ 0 -> continue
+ 1 -> foo { continue }
+ 2 -> foo(@SomeAnnotation { continue })
+ 3 -> foo(fun () { continue })
+ 4 -> foo(@SomeAnnotation fun () { continue })
+ }
}
}
}
fun test3() {
while (true) {
- class LocalClass {
+ class LocalClass(val tag: Int) {
init {
- continue
+ when(tag) {
+ 0 -> continue
+ 1 -> foo { continue }
+ 2 -> foo(@SomeAnnotation { continue })
+ 3 -> foo(fun () { continue })
+ 4 -> foo(@SomeAnnotation fun () { continue })
+ }
}
fun foo() {
- break
+ when(tag) {
+ 0 -> break
+ 1 -> foo { break }
+ 2 -> foo(@SomeAnnotation { break })
+ 3 -> foo(fun () { break })
+ 4 -> foo(@SomeAnnotation fun () { break })
+ }
}
}
}
}
-fun test4() {
+fun test4(tag: Int) {
while (true) {
object: Any() {
init {
- break
+ when(tag) {
+ 0 -> break
+ 1 -> foo { break }
+ 2 -> foo(@SomeAnnotation { break })
+ 3 -> foo(fun () { break })
+ 4 -> foo(@SomeAnnotation fun () { break })
+ }
}
}
}
@@ -40,12 +79,15 @@ fun test4() {
fun test5() {
while (true) {
- class LocalClass(val x: Int) {
- constructor() : this(42) {
- break
- }
- constructor(y: Double) : this(y.toInt()) {
- continue
+ class LocalClass(val s: String) {
+ constructor(tag: Int) : this("") {
+ when(tag) {
+ 0 -> break
+ 1 -> foo { break }
+ 2 -> foo(@SomeAnnotation { break })
+ 3 -> foo(fun () { break })
+ 4 -> foo(@SomeAnnotation fun () { break })
+ }
}
}
}
@@ -53,12 +95,24 @@ fun test5() {
fun test6() {
while (true) {
- class LocalClass(val x: Int) {
+ class LocalClass(val tag: Int) {
init {
- break
+ when(tag) {
+ 0 -> break
+ 1 -> foo { break }
+ 2 -> foo(@SomeAnnotation { break })
+ 3 -> foo(fun () { break })
+ 4 -> foo(@SomeAnnotation fun () { break })
+ }
}
init {
- continue
+ when(tag) {
+ 0 -> continue
+ 1 -> foo { continue }
+ 2 -> foo(@SomeAnnotation { continue })
+ 3 -> foo(fun () { continue })
+ 4 -> foo(@SomeAnnotation fun () { continue })
+ }
}
}
}
@@ -66,12 +120,26 @@ fun test6() {
fun test7() {
while (true) {
- class LocalClass {
+ class LocalClass(val tag: Int) {
val x: Int = if (true) {
- break
+ when(tag) {
+ 0 -> break
+ 1 -> foo { break }
+ 2 -> foo(@SomeAnnotation { break })
+ 3 -> foo(fun (): Int { break })
+ 4 -> foo(@SomeAnnotation fun (): Int { break })
+ else -> 1
+ }
}
else {
- continue
+ when(tag) {
+ 0 -> continue
+ 1 -> foo { continue }
+ 2 -> foo(@SomeAnnotation { continue })
+ 3 -> foo(fun (): Int { continue })
+ 4 -> foo(@SomeAnnotation fun (): Int { continue })
+ else -> 2
+ }
}
}
}
@@ -80,7 +148,16 @@ fun test7() {
fun test8() {
while (true) {
class LocalClass(val x: Int) {
- constructor() : this(if (true) { 42 } else { break })
+ constructor(tag: Int, unused: Boolean) : this(
+ when(tag) {
+ 0 -> break
+ 1 -> foo { break }
+ 2 -> foo(@SomeAnnotation { break })
+ 3 -> foo(fun (): Int { break })
+ 4 -> foo(@SomeAnnotation fun (): Int { break })
+ else -> 1
+ }
+ )
}
}
}
\ No newline at end of file
diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/breakInsideLocal.txt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/breakInsideLocal.txt
index 8eb87ce2285..d92785120aa 100644
--- a/compiler/testData/diagnostics/tests/controlFlowAnalysis/breakInsideLocal.txt
+++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/breakInsideLocal.txt
@@ -1,10 +1,19 @@
package
+public inline fun *0*/ T> foo(/*0*/ block: () -> T): T
public fun test(): kotlin.Unit
public fun test2(): kotlin.Unit
public fun test3(): kotlin.Unit
-public fun test4(): kotlin.Unit
+public fun test4(/*0*/ tag: kotlin.Int): kotlin.Unit
public fun test5(): kotlin.Unit
public fun test6(): kotlin.Unit
public fun test7(): kotlin.Unit
public fun test8(): kotlin.Unit
+
+@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.EXPRESSION}) @kotlin.annotation.Retention(value = AnnotationRetention.SOURCE) public final annotation class SomeAnnotation : kotlin.Annotation {
+ public constructor SomeAnnotation()
+ public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
+ public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
+ public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
+}
+
diff --git a/compiler/testData/ir/irText/expressions/badInlinedBreakContinue.ir.txt b/compiler/testData/ir/irText/expressions/badInlinedBreakContinue.ir.txt
new file mode 100644
index 00000000000..3e4f5ee7550
--- /dev/null
+++ b/compiler/testData/ir/irText/expressions/badInlinedBreakContinue.ir.txt
@@ -0,0 +1,344 @@
+FILE fqName: fileName:/badInlinedBreakContinue.kt
+ FUN name:foo visibility:public modality:FINAL <> (block:kotlin.Function0) returnType:kotlin.Unit [inline]
+ VALUE_PARAMETER name:block index:0 type:kotlin.Function0
+ BLOCK_BODY
+ CALL 'public abstract fun invoke (): R of kotlin.Function0 [operator] declared in kotlin.Function0' type=kotlin.Unit origin=INVOKE
+ $this: GET_VAR 'block: kotlin.Function0 declared in .foo' type=kotlin.Function0 origin=VARIABLE_AS_FUNCTION
+ FUN name:bar visibility:public modality:FINAL <> (block1:kotlin.Function0, block2:kotlin.Function0) returnType:kotlin.Unit [inline]
+ VALUE_PARAMETER name:block1 index:0 type:kotlin.Function0
+ VALUE_PARAMETER name:block2 index:1 type:kotlin.Function0 [noinline]
+ BLOCK_BODY
+ CALL 'public abstract fun invoke (): R of kotlin.Function0 [operator] declared in kotlin.Function0' type=kotlin.Unit origin=INVOKE
+ $this: GET_VAR 'block1: kotlin.Function0 declared in .bar' type=kotlin.Function0 origin=VARIABLE_AS_FUNCTION
+ CALL 'public abstract fun invoke (): R of kotlin.Function0 [operator] declared in kotlin.Function0' type=kotlin.Unit origin=INVOKE
+ $this: GET_VAR 'block2: kotlin.Function0 [noinline] declared in .bar' type=kotlin.Function0 origin=VARIABLE_AS_FUNCTION
+ FUN name:myForEach visibility:public modality:FINAL ($receiver:kotlin.collections.Iterable.myForEach>, action:kotlin.Function1.myForEach, kotlin.Unit>) returnType:kotlin.Unit [inline]
+ TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Any?] reified:false
+ $receiver: VALUE_PARAMETER name: type:kotlin.collections.Iterable.myForEach>
+ VALUE_PARAMETER name:action index:0 type:kotlin.Function1.myForEach, kotlin.Unit>
+ BLOCK_BODY
+ BLOCK type=kotlin.Unit origin=FOR_LOOP
+ VAR FOR_LOOP_ITERATOR name:tmp_0 type:kotlin.collections.Iterator.myForEach> [val]
+ CALL 'public abstract fun iterator (): kotlin.collections.Iterator [operator] declared in kotlin.collections.Iterable' type=kotlin.collections.Iterator.myForEach> origin=FOR_LOOP_ITERATOR
+ $this: GET_VAR ': kotlin.collections.Iterable.myForEach> declared in .myForEach' type=kotlin.collections.Iterable.myForEach> origin=null
+ WHILE label=null origin=FOR_LOOP_INNER_WHILE
+ condition: CALL 'public abstract fun hasNext (): kotlin.Boolean [operator] declared in kotlin.collections.Iterator' type=kotlin.Boolean origin=FOR_LOOP_HAS_NEXT
+ $this: GET_VAR 'val tmp_0: kotlin.collections.Iterator.myForEach> [val] declared in .myForEach' type=kotlin.collections.Iterator.myForEach> origin=null
+ body: BLOCK type=kotlin.Unit origin=FOR_LOOP_INNER_WHILE
+ VAR FOR_LOOP_VARIABLE name:element type:T of .myForEach [val]
+ CALL 'public abstract fun next (): T of kotlin.collections.Iterator [operator] declared in kotlin.collections.Iterator' type=T of .myForEach origin=FOR_LOOP_NEXT
+ $this: GET_VAR 'val tmp_0: kotlin.collections.Iterator.myForEach> [val] declared in .myForEach' type=kotlin.collections.Iterator.myForEach> origin=null
+ CALL 'public abstract fun invoke (p1: P1 of kotlin.Function1): R of kotlin.Function1 [operator] declared in kotlin.Function1' type=kotlin.Unit origin=INVOKE
+ $this: GET_VAR 'action: kotlin.Function1.myForEach, kotlin.Unit> declared in .myForEach' type=kotlin.Function1.myForEach, kotlin.Unit> origin=VARIABLE_AS_FUNCTION
+ p1: GET_VAR 'val element: T of .myForEach [val] declared in .myForEach' type=T of .myForEach origin=null
+ FUN name:test1 visibility:public modality:FINAL <> () returnType:kotlin.Unit
+ BLOCK_BODY
+ ERROR_EXPR '{break}()
+ {continue}()' type=IrErrorType([Error type: Error expression type])
+ CALL 'public abstract fun invoke (): R of kotlin.Function0 [operator] declared in kotlin.Function0' type=kotlin.Unit origin=INVOKE
+ $this: FUN_EXPR type=kotlin.Function0 origin=ANONYMOUS_FUNCTION
+ FUN LOCAL_FUNCTION name: visibility:local modality:FINAL <> () returnType:kotlin.Unit
+ BLOCK_BODY
+ ERROR_EXPR 'Loop not found for break expression: break' type=kotlin.Nothing
+ CALL 'public abstract fun invoke (): R of kotlin.Function0 [operator] declared in kotlin.Function0' type=kotlin.Unit origin=INVOKE
+ $this: FUN_EXPR type=kotlin.Function0 origin=ANONYMOUS_FUNCTION
+ FUN LOCAL_FUNCTION name: visibility:local modality:FINAL <> () returnType:kotlin.Unit
+ BLOCK_BODY
+ ERROR_EXPR 'Loop not found for continue expression: continue' type=kotlin.Nothing
+ CALL 'public final fun foo (block: kotlin.Function0): kotlin.Unit [inline] declared in ' type=kotlin.Unit origin=null
+ block: FUN_EXPR type=kotlin.Function0 origin=LAMBDA
+ FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:kotlin.Unit
+ BLOCK_BODY
+ ERROR_EXPR 'Loop not found for break expression: break' type=kotlin.Nothing
+ CALL 'public final fun foo (block: kotlin.Function0): kotlin.Unit [inline] declared in ' type=kotlin.Unit origin=null
+ block: FUN_EXPR type=kotlin.Function0 origin=LAMBDA
+ FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:kotlin.Unit
+ BLOCK_BODY
+ ERROR_EXPR 'Loop not found for continue expression: continue' type=kotlin.Nothing
+ CALL 'public final fun foo (block: kotlin.Function0): kotlin.Unit [inline] declared in ' type=kotlin.Unit origin=null
+ block: FUN_EXPR type=kotlin.Function0 origin=ANONYMOUS_FUNCTION
+ FUN LOCAL_FUNCTION name: visibility:local modality:FINAL <> () returnType:kotlin.Unit
+ BLOCK_BODY
+ ERROR_EXPR 'Loop not found for break expression: break' type=kotlin.Nothing
+ CALL 'public final fun foo (block: kotlin.Function0): kotlin.Unit [inline] declared in ' type=kotlin.Unit origin=null
+ block: FUN_EXPR type=kotlin.Function0 origin=ANONYMOUS_FUNCTION
+ FUN LOCAL_FUNCTION name: visibility:local modality:FINAL <> () returnType:kotlin.Unit
+ BLOCK_BODY
+ ERROR_EXPR 'Loop not found for continue expression: continue' type=kotlin.Nothing
+ FUN name:test2 visibility:public modality:FINAL <> () returnType:kotlin.Unit
+ BLOCK_BODY
+ WHILE label=L1 origin=WHILE_LOOP
+ condition: CONST Boolean type=kotlin.Boolean value=true
+ body: BLOCK type=kotlin.Unit origin=null
+ ERROR_EXPR '{break@ERROR}()
+ {continue@ERROR}()' type=IrErrorType([Error type: Error expression type])
+ CALL 'public abstract fun invoke (): R of kotlin.Function0 [operator] declared in kotlin.Function0' type=kotlin.Unit origin=INVOKE
+ $this: FUN_EXPR type=kotlin.Function0 origin=ANONYMOUS_FUNCTION
+ FUN LOCAL_FUNCTION name: visibility:local modality:FINAL <> () returnType:kotlin.Unit
+ BLOCK_BODY
+ ERROR_EXPR 'Loop not found for break expression: break@ERROR' type=kotlin.Nothing
+ CALL 'public abstract fun invoke (): R of kotlin.Function0 [operator] declared in kotlin.Function0' type=kotlin.Unit origin=INVOKE
+ $this: FUN_EXPR type=kotlin.Function0 origin=ANONYMOUS_FUNCTION
+ FUN LOCAL_FUNCTION name: visibility:local modality:FINAL <> () returnType:kotlin.Unit
+ BLOCK_BODY
+ ERROR_EXPR 'Loop not found for continue expression: continue@ERROR' type=kotlin.Nothing
+ CALL 'public final fun foo (block: kotlin.Function0): kotlin.Unit [inline] declared in ' type=kotlin.Unit origin=null
+ block: FUN_EXPR type=kotlin.Function0 origin=LAMBDA
+ FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:kotlin.Unit
+ BLOCK_BODY
+ ERROR_EXPR 'Loop not found for break expression: break@ERROR' type=kotlin.Nothing
+ CALL 'public final fun foo (block: kotlin.Function0): kotlin.Unit [inline] declared in ' type=kotlin.Unit origin=null
+ block: FUN_EXPR type=kotlin.Function0 origin=LAMBDA
+ FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:kotlin.Unit
+ BLOCK_BODY
+ ERROR_EXPR 'Loop not found for continue expression: continue@ERROR' type=kotlin.Nothing
+ CALL 'public final fun foo (block: kotlin.Function0): kotlin.Unit [inline] declared in ' type=kotlin.Unit origin=null
+ block: FUN_EXPR type=kotlin.Function0 origin=ANONYMOUS_FUNCTION
+ FUN LOCAL_FUNCTION name: visibility:local modality:FINAL <> () returnType:kotlin.Unit
+ BLOCK_BODY
+ ERROR_EXPR 'Loop not found for break expression: break@ERROR' type=kotlin.Nothing
+ CALL 'public final fun foo (block: kotlin.Function0): kotlin.Unit [inline] declared in ' type=kotlin.Unit origin=null
+ block: FUN_EXPR type=kotlin.Function0 origin=ANONYMOUS_FUNCTION
+ FUN LOCAL_FUNCTION name: visibility:local modality:FINAL <> () returnType:kotlin.Unit
+ BLOCK_BODY
+ ERROR_EXPR 'Loop not found for continue expression: continue@ERROR' type=kotlin.Nothing
+ FUN name:test3 visibility:public modality:FINAL <> () returnType:kotlin.Unit
+ BLOCK_BODY
+ WHILE label=L1 origin=WHILE_LOOP
+ condition: CONST Boolean type=kotlin.Boolean value=true
+ body: BLOCK type=kotlin.Unit origin=null
+ VAR name:lambda type:kotlin.Function0 [val]
+ FUN_EXPR type=kotlin.Function0 origin=LAMBDA
+ FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:kotlin.Unit
+ BLOCK_BODY
+ ERROR_EXPR '{break@L1}()
+ {continue@L1}()' type=IrErrorType([Error type: Error expression type])
+ CALL 'public abstract fun invoke (): R of kotlin.Function0 [operator] declared in kotlin.Function0' type=kotlin.Unit origin=INVOKE
+ $this: FUN_EXPR type=kotlin.Function0 origin=ANONYMOUS_FUNCTION
+ FUN LOCAL_FUNCTION name: visibility:local modality:FINAL <> () returnType:kotlin.Unit
+ BLOCK_BODY
+ ERROR_EXPR 'Loop not found for break expression: break@L1' type=kotlin.Nothing
+ CALL 'public abstract fun invoke (): R of kotlin.Function0 [operator] declared in kotlin.Function0' type=kotlin.Unit origin=INVOKE
+ $this: FUN_EXPR type=kotlin.Function0 origin=ANONYMOUS_FUNCTION
+ FUN LOCAL_FUNCTION name: visibility:local modality:FINAL <> () returnType:kotlin.Unit
+ BLOCK_BODY
+ ERROR_EXPR 'Loop not found for continue expression: continue@L1' type=kotlin.Nothing
+ CALL 'public final fun foo (block: kotlin.Function0): kotlin.Unit [inline] declared in ' type=kotlin.Unit origin=null
+ block: FUN_EXPR type=kotlin.Function0 origin=LAMBDA
+ FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:kotlin.Unit
+ BLOCK_BODY
+ ERROR_EXPR 'Loop not found for break expression: break@L1' type=kotlin.Nothing
+ CALL 'public final fun foo (block: kotlin.Function0): kotlin.Unit [inline] declared in ' type=kotlin.Unit origin=null
+ block: FUN_EXPR type=kotlin.Function0 origin=LAMBDA
+ FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:kotlin.Unit
+ BLOCK_BODY
+ ERROR_EXPR 'Loop not found for continue expression: continue@L1' type=kotlin.Nothing
+ CALL 'public final fun foo (block: kotlin.Function0): kotlin.Unit [inline] declared in ' type=kotlin.Unit origin=null
+ block: FUN_EXPR type=kotlin.Function0 origin=ANONYMOUS_FUNCTION
+ FUN LOCAL_FUNCTION name: visibility:local modality:FINAL <> () returnType:kotlin.Unit
+ BLOCK_BODY
+ ERROR_EXPR 'Loop not found for break expression: break@L1' type=kotlin.Nothing
+ CALL 'public final fun foo (block: kotlin.Function0): kotlin.Unit [inline] declared in ' type=kotlin.Unit origin=null
+ block: FUN_EXPR type=kotlin.Function0 origin=ANONYMOUS_FUNCTION
+ FUN LOCAL_FUNCTION name: visibility:local modality:FINAL <> () returnType:kotlin.Unit
+ BLOCK_BODY
+ ERROR_EXPR 'Loop not found for continue expression: continue@L1' type=kotlin.Nothing
+ FUN name:test4 visibility:public modality:FINAL <> () returnType:kotlin.Unit
+ BLOCK_BODY
+ WHILE label=null origin=WHILE_LOOP
+ condition: CALL 'public abstract fun invoke (): R of kotlin.Function0 [operator] declared in kotlin.Function0' type=kotlin.Nothing origin=INVOKE
+ $this: FUN_EXPR type=kotlin.Function0 origin=LAMBDA
+ FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:kotlin.Nothing
+ BLOCK_BODY
+ RETURN type=kotlin.Nothing from='local final fun (): kotlin.Nothing declared in .test4'
+ ERROR_EXPR 'Loop not found for break expression: break' type=kotlin.Nothing
+ body: BLOCK type=kotlin.Unit origin=null
+ WHILE label=null origin=WHILE_LOOP
+ condition: CALL 'public abstract fun invoke (): R of kotlin.Function0 [operator] declared in kotlin.Function0' type=kotlin.Nothing origin=INVOKE
+ $this: FUN_EXPR type=kotlin.Function0 origin=LAMBDA
+ FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:kotlin.Nothing
+ BLOCK_BODY
+ RETURN type=kotlin.Nothing from='local final fun (): kotlin.Nothing declared in .test4'
+ ERROR_EXPR 'Loop not found for continue expression: continue' type=kotlin.Nothing
+ body: BLOCK type=kotlin.Unit origin=null
+ WHILE label=null origin=WHILE_LOOP
+ condition: TYPE_OP type=kotlin.Boolean origin=IMPLICIT_CAST typeOperand=kotlin.Boolean
+ CALL 'public abstract fun invoke (): R of kotlin.Function0 [operator] declared in kotlin.Function0' type=kotlin.Unit origin=INVOKE
+ $this: FUN_EXPR type=kotlin.Function0 origin=ANONYMOUS_FUNCTION
+ FUN LOCAL_FUNCTION name: visibility:local modality:FINAL <> () returnType:kotlin.Unit
+ BLOCK_BODY
+ ERROR_EXPR 'Loop not found for break expression: break' type=kotlin.Nothing
+ body: BLOCK type=kotlin.Unit origin=null
+ WHILE label=null origin=WHILE_LOOP
+ condition: TYPE_OP type=kotlin.Boolean origin=IMPLICIT_CAST typeOperand=kotlin.Boolean
+ CALL 'public abstract fun invoke (): R of kotlin.Function0 [operator] declared in kotlin.Function0' type=kotlin.Unit origin=INVOKE
+ $this: FUN_EXPR type=kotlin.Function0 origin=ANONYMOUS_FUNCTION
+ FUN LOCAL_FUNCTION name: visibility:local modality:FINAL <> () returnType:kotlin.Unit
+ BLOCK_BODY
+ ERROR_EXPR 'Loop not found for continue expression: continue' type=kotlin.Nothing
+ body: BLOCK type=kotlin.Unit origin=null
+ WHILE label=null origin=WHILE_LOOP
+ condition: TYPE_OP type=kotlin.Boolean origin=IMPLICIT_CAST typeOperand=kotlin.Boolean
+ CALL 'public final fun foo (block: kotlin.Function0): kotlin.Unit [inline] declared in ' type=kotlin.Unit origin=null
+ block: FUN_EXPR type=kotlin.Function0 origin=LAMBDA
+ FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:kotlin.Unit
+ BLOCK_BODY
+ ERROR_EXPR 'Loop not found for break expression: break' type=kotlin.Nothing
+ body: BLOCK type=kotlin.Unit origin=null
+ WHILE label=null origin=WHILE_LOOP
+ condition: TYPE_OP type=kotlin.Boolean origin=IMPLICIT_CAST typeOperand=kotlin.Boolean
+ CALL 'public final fun foo (block: kotlin.Function0): kotlin.Unit [inline] declared in ' type=kotlin.Unit origin=null
+ block: FUN_EXPR type=kotlin.Function0 origin=LAMBDA
+ FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:kotlin.Unit
+ BLOCK_BODY
+ ERROR_EXPR 'Loop not found for continue expression: continue' type=kotlin.Nothing
+ body: BLOCK type=kotlin.Unit origin=null
+ WHILE label=null origin=WHILE_LOOP
+ condition: TYPE_OP type=kotlin.Boolean origin=IMPLICIT_CAST typeOperand=kotlin.Boolean
+ CALL 'public final fun foo (block: kotlin.Function0): kotlin.Unit [inline] declared in ' type=kotlin.Unit origin=null
+ block: FUN_EXPR type=kotlin.Function0 origin=ANONYMOUS_FUNCTION
+ FUN LOCAL_FUNCTION name: visibility:local modality:FINAL <> () returnType:kotlin.Unit
+ BLOCK_BODY
+ ERROR_EXPR 'Loop not found for break expression: break' type=kotlin.Nothing
+ body: BLOCK type=kotlin.Unit origin=null
+ WHILE label=null origin=WHILE_LOOP
+ condition: TYPE_OP type=kotlin.Boolean origin=IMPLICIT_CAST typeOperand=kotlin.Boolean
+ CALL 'public final fun foo (block: kotlin.Function0): kotlin.Unit [inline] declared in ' type=kotlin.Unit origin=null
+ block: FUN_EXPR type=kotlin.Function0 origin=ANONYMOUS_FUNCTION
+ FUN LOCAL_FUNCTION name: visibility:local modality:FINAL <> () returnType:kotlin.Unit
+ BLOCK_BODY
+ ERROR_EXPR 'Loop not found for continue expression: continue' type=kotlin.Nothing
+ body: BLOCK type=kotlin.Unit origin=null
+ FUN name:test5 visibility:public modality:FINAL <> () returnType:kotlin.Unit
+ BLOCK_BODY
+ CALL 'public final fun forEach (action: kotlin.Function1): kotlin.Unit [inline] declared in kotlin.collections.CollectionsKt' type=kotlin.Unit origin=null
+ : kotlin.Int
+ $receiver: CALL 'public final fun listOf (vararg elements: T of kotlin.collections.CollectionsKt.listOf): kotlin.collections.List declared in kotlin.collections.CollectionsKt' type=kotlin.collections.List origin=null
+ : kotlin.Int
+ elements: VARARG type=kotlin.Array varargElementType=kotlin.Int
+ CONST Int type=kotlin.Int value=1
+ CONST Int type=kotlin.Int value=2
+ CONST Int type=kotlin.Int value=3
+ action: FUN_EXPR type=kotlin.Function1 origin=LAMBDA
+ FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> (i:kotlin.Int) returnType:kotlin.Unit
+ VALUE_PARAMETER name:i index:0 type:kotlin.Int
+ BLOCK_BODY
+ WHEN type=kotlin.Unit origin=IF
+ BRANCH
+ if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
+ arg0: GET_VAR 'i: kotlin.Int declared in .test5.' type=kotlin.Int origin=null
+ arg1: CONST Int type=kotlin.Int value=2
+ then: ERROR_EXPR 'Loop not found for break expression: break' type=kotlin.Nothing
+ CALL 'public final fun forEach (action: kotlin.Function1): kotlin.Unit [inline] declared in kotlin.collections.CollectionsKt' type=kotlin.Unit origin=null
+ : kotlin.Int
+ $receiver: CALL 'public final fun listOf (vararg elements: T of kotlin.collections.CollectionsKt.listOf): kotlin.collections.List declared in kotlin.collections.CollectionsKt' type=kotlin.collections.List origin=null
+ : kotlin.Int
+ elements: VARARG type=kotlin.Array varargElementType=kotlin.Int
+ CONST Int type=kotlin.Int value=1
+ CONST Int type=kotlin.Int value=2
+ CONST Int type=kotlin.Int value=3
+ action: FUN_EXPR type=kotlin.Function1 origin=LAMBDA
+ FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> (i:kotlin.Int) returnType:kotlin.Unit
+ VALUE_PARAMETER name:i index:0 type:kotlin.Int
+ BLOCK_BODY
+ WHEN type=kotlin.Unit origin=IF
+ BRANCH
+ if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
+ arg0: GET_VAR 'i: kotlin.Int declared in .test5.' type=kotlin.Int origin=null
+ arg1: CONST Int type=kotlin.Int value=2
+ then: ERROR_EXPR 'Loop not found for continue expression: continue' type=kotlin.Nothing
+ CALL 'public final fun forEach (action: kotlin.Function1): kotlin.Unit [inline] declared in kotlin.collections.CollectionsKt' type=kotlin.Unit origin=null
+ : kotlin.Int
+ $receiver: CALL 'public final fun listOf (vararg elements: T of kotlin.collections.CollectionsKt.listOf): kotlin.collections.List declared in kotlin.collections.CollectionsKt' type=kotlin.collections.List origin=null
+ : kotlin.Int
+ elements: VARARG type=kotlin.Array varargElementType=kotlin.Int
+ CONST Int type=kotlin.Int value=1
+ CONST Int type=kotlin.Int value=2
+ CONST Int type=kotlin.Int value=3
+ action: FUN_EXPR type=kotlin.Function1 origin=ANONYMOUS_FUNCTION
+ FUN LOCAL_FUNCTION name: visibility:local modality:FINAL <> (i:kotlin.Int) returnType:kotlin.Unit
+ VALUE_PARAMETER name:i index:0 type:kotlin.Int
+ BLOCK_BODY
+ WHEN type=kotlin.Unit origin=IF
+ BRANCH
+ if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
+ arg0: GET_VAR 'i: kotlin.Int declared in .test5.' type=kotlin.Int origin=null
+ arg1: CONST Int type=kotlin.Int value=2
+ then: ERROR_EXPR 'Loop not found for break expression: break' type=kotlin.Nothing
+ CALL 'public final fun forEach (action: kotlin.Function1): kotlin.Unit [inline] declared in kotlin.collections.CollectionsKt' type=kotlin.Unit origin=null
+ : kotlin.Int
+ $receiver: CALL 'public final fun listOf (vararg elements: T of kotlin.collections.CollectionsKt.listOf): kotlin.collections.List declared in kotlin.collections.CollectionsKt' type=kotlin.collections.List origin=null
+ : kotlin.Int
+ elements: VARARG type=kotlin.Array varargElementType=kotlin.Int
+ CONST Int type=kotlin.Int value=1
+ CONST Int type=kotlin.Int value=2
+ CONST Int type=kotlin.Int value=3
+ action: FUN_EXPR type=kotlin.Function1 origin=ANONYMOUS_FUNCTION
+ FUN LOCAL_FUNCTION name: visibility:local modality:FINAL <> (i:kotlin.Int) returnType:kotlin.Unit
+ VALUE_PARAMETER name:i index:0 type:kotlin.Int
+ BLOCK_BODY
+ WHEN type=kotlin.Unit origin=IF
+ BRANCH
+ if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
+ arg0: GET_VAR 'i: kotlin.Int declared in .test5.' type=kotlin.Int origin=null
+ arg1: CONST Int type=kotlin.Int value=2
+ then: ERROR_EXPR 'Loop not found for continue expression: continue' type=kotlin.Nothing
+ FUN name:test6 visibility:public modality:FINAL <> () returnType:kotlin.Unit
+ BLOCK_BODY
+ WHILE label=null origin=WHILE_LOOP
+ condition: CONST Boolean type=kotlin.Boolean value=true
+ body: BLOCK type=kotlin.Unit origin=null
+ CALL 'public final fun bar (block1: kotlin.Function0, block2: kotlin.Function0): kotlin.Unit [inline] declared in ' type=kotlin.Unit origin=null
+ block1: FUN_EXPR type=kotlin.Function0 origin=LAMBDA
+ FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:kotlin.Unit
+ BLOCK_BODY
+ RETURN type=kotlin.Nothing from='local final fun (): kotlin.Unit declared in .test6'
+ GET_OBJECT 'CLASS IR_EXTERNAL_DECLARATION_STUB OBJECT name:Unit modality:FINAL visibility:public superTypes:[kotlin.Any]' type=kotlin.Unit
+ block2: FUN_EXPR type=kotlin.Function0 origin=LAMBDA
+ FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:kotlin.Unit
+ BLOCK_BODY
+ ERROR_EXPR 'Loop not found for break expression: break' type=kotlin.Nothing
+ CALL 'public final fun bar (block1: kotlin.Function0, block2: kotlin.Function0): kotlin.Unit [inline] declared in ' type=kotlin.Unit origin=null
+ block1: FUN_EXPR type=kotlin.Function0 origin=LAMBDA
+ FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:kotlin.Unit
+ BLOCK_BODY
+ RETURN type=kotlin.Nothing from='local final fun (): kotlin.Unit declared in .test6'
+ GET_OBJECT 'CLASS IR_EXTERNAL_DECLARATION_STUB OBJECT name:Unit modality:FINAL visibility:public superTypes:[kotlin.Any]' type=kotlin.Unit
+ block2: FUN_EXPR type=kotlin.Function0 origin=LAMBDA
+ FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:kotlin.Unit
+ BLOCK_BODY
+ ERROR_EXPR 'Loop not found for continue expression: continue' type=kotlin.Nothing
+ CALL 'public final fun bar (block1: kotlin.Function0, block2: kotlin.Function0): kotlin.Unit [inline] declared in ' type=kotlin.Unit origin=null
+ block1: FUN_EXPR type=kotlin.Function0 origin=ANONYMOUS_FUNCTION
+ FUN LOCAL_FUNCTION name: visibility:local modality:FINAL <> () returnType:kotlin.Unit
+ BLOCK_BODY
+ block2: FUN_EXPR type=kotlin.Function0 origin=ANONYMOUS_FUNCTION
+ FUN LOCAL_FUNCTION name: visibility:local modality:FINAL <> () returnType:kotlin.Unit
+ BLOCK_BODY
+ ERROR_EXPR 'Loop not found for break expression: break' type=kotlin.Nothing
+ CALL 'public final fun bar (block1: kotlin.Function0, block2: kotlin.Function0): kotlin.Unit [inline] declared in ' type=kotlin.Unit origin=null
+ block1: FUN_EXPR type=kotlin.Function0 origin=ANONYMOUS_FUNCTION
+ FUN LOCAL_FUNCTION name: visibility:local modality:FINAL <> () returnType:kotlin.Unit
+ BLOCK_BODY
+ block2: FUN_EXPR type=kotlin.Function0 origin=ANONYMOUS_FUNCTION
+ FUN LOCAL_FUNCTION name: visibility:local modality:FINAL <> () returnType:kotlin.Unit
+ BLOCK_BODY
+ ERROR_EXPR 'Loop not found for continue expression: continue' type=kotlin.Nothing
+ FUN name:test7 visibility:public modality:FINAL <> () returnType:kotlin.Unit
+ BLOCK_BODY
+ CALL 'public final fun myForEach (action: kotlin.Function1.myForEach, kotlin.Unit>): kotlin.Unit [inline] declared in ' type=kotlin.Unit origin=null
+ : kotlin.Int
+ $receiver: CALL 'public final fun rangeTo (other: kotlin.Int): kotlin.ranges.IntRange [operator] declared in kotlin.Int' type=kotlin.ranges.IntRange origin=RANGE
+ $this: CONST Int type=kotlin.Int value=1
+ other: CONST Int type=kotlin.Int value=3
+ action: FUN_EXPR type=kotlin.Function1 origin=LAMBDA
+ FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> (i:kotlin.Int) returnType:kotlin.Unit
+ VALUE_PARAMETER name:i index:0 type:kotlin.Int
+ BLOCK_BODY
+ WHEN type=kotlin.Unit origin=IF
+ BRANCH
+ if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
+ arg0: GET_VAR 'i: kotlin.Int declared in .test7.' type=kotlin.Int origin=null
+ arg1: CONST Int type=kotlin.Int value=2
+ then: BLOCK type=kotlin.Unit origin=null
+ ERROR_EXPR 'Loop not found for break expression: break' type=kotlin.Nothing
diff --git a/compiler/testData/ir/irText/expressions/badInlinedBreakContinue.kt b/compiler/testData/ir/irText/expressions/badInlinedBreakContinue.kt
new file mode 100644
index 00000000000..243e2f28b2b
--- /dev/null
+++ b/compiler/testData/ir/irText/expressions/badInlinedBreakContinue.kt
@@ -0,0 +1,111 @@
+// LANGUAGE: +BreakContinueInInlineLambdas
+// TARGET_BACKEND: JVM_IR
+// IGNORE_BACKEND_FIR: JVM_IR
+// !IGNORE_ERRORS
+// WITH_STDLIB
+
+inline fun foo(block: () -> Unit) { block() }
+
+inline fun bar(block1: () -> Unit, noinline block2: () -> Unit) {
+ block1()
+ block2()
+}
+
+inline fun Iterable.myForEach(action: (T) -> Unit): Unit {
+ for (element in this) action(element)
+}
+
+fun test1() {
+ {break}()
+ {continue}()
+
+ (fun () {break})()
+ (fun () {continue})()
+
+ foo {break}
+ foo {continue}
+
+ foo(fun () {break})
+ foo(fun () {continue})
+}
+
+fun test2() {
+ L1@ while (true) {
+ {break@ERROR}()
+ {continue@ERROR}()
+
+ (fun () {break@ERROR})()
+ (fun () {continue@ERROR})()
+
+ foo {break@ERROR}
+ foo {continue@ERROR}
+
+ foo(fun () {break@ERROR})
+ foo(fun () {continue@ERROR})
+ }
+}
+
+fun test3() {
+ L1@ while (true) {
+ val lambda = {
+ {break@L1}()
+ {continue@L1}()
+
+ (fun () {break@L1})()
+ (fun () {continue@L1})()
+
+ foo {break@L1}
+ foo {continue@L1}
+
+ foo(fun () {break@L1})
+ foo(fun () {continue@L1})
+ }
+ }
+}
+
+fun test4() {
+ while ({ break }()) {
+ }
+ while ({ continue }()) {
+ }
+
+ while ((fun() { break })()) {
+ }
+ while ((fun() { continue })()) {
+ }
+
+ while (foo { break }) {
+ }
+ while (foo { continue }) {
+ }
+
+ while (foo(fun() { break })) {
+ }
+ while (foo(fun() { continue })) {
+ }
+}
+
+fun test5() {
+ listOf(1, 2, 3).forEach { i -> if (i == 2) break }
+ listOf(1, 2, 3).forEach { i -> if (i == 2) continue }
+ listOf(1, 2, 3).forEach(fun (i: Int) { if (i == 2) break })
+ listOf(1, 2, 3).forEach(fun (i: Int) { if (i == 2) continue })
+}
+
+fun test6() {
+ while (true) {
+ bar({}, {break})
+ bar({}, {continue})
+
+ bar(fun () {}, fun () {break})
+ bar(fun () {}, fun () {continue})
+ }
+}
+
+fun test7() {
+ (1..3).myForEach { i ->
+ if (i == 2) {
+ break
+ }
+ }
+}
\ No newline at end of file
diff --git a/compiler/testData/ir/irText/expressions/badInlinedBreakContinue.kt.txt b/compiler/testData/ir/irText/expressions/badInlinedBreakContinue.kt.txt
new file mode 100644
index 00000000000..d90a47bca5c
--- /dev/null
+++ b/compiler/testData/ir/irText/expressions/badInlinedBreakContinue.kt.txt
@@ -0,0 +1,222 @@
+inline fun foo(block: Function0) {
+ block.invoke()
+}
+
+inline fun bar(block1: Function0, noinline block2: Function0) {
+ block1.invoke()
+ block2.invoke()
+}
+
+inline fun Iterable.myForEach(action: Function1) {
+ { // BLOCK
+ val tmp0_iterator: Iterator = .iterator()
+ while (tmp0_iterator.hasNext()) { // BLOCK
+ val element: T = tmp0_iterator.next()
+ action.invoke(p1 = element)
+ }
+ }
+}
+
+fun test1() {
+ error("") /* ErrorExpression */
+ local fun () {
+ error("") /* ErrorExpression */
+ }
+.invoke()
+ local fun () {
+ error("") /* ErrorExpression */
+ }
+.invoke()
+ foo(block = local fun () {
+ error("") /* ErrorExpression */
+ }
+)
+ foo(block = local fun () {
+ error("") /* ErrorExpression */
+ }
+)
+ foo(block = local fun () {
+ error("") /* ErrorExpression */
+ }
+)
+ foo(block = local fun () {
+ error("") /* ErrorExpression */
+ }
+)
+}
+
+fun test2() {
+ L1@ while (true) { // BLOCK
+ error("") /* ErrorExpression */
+ local fun () {
+ error("") /* ErrorExpression */
+ }
+.invoke()
+ local fun () {
+ error("") /* ErrorExpression */
+ }
+.invoke()
+ foo(block = local fun () {
+ error("") /* ErrorExpression */
+ }
+)
+ foo(block = local fun